예제 #1
0
def plot_LO_horiz_stripes():
    '''
    This uses data that has been processed through pik1 but w/ the hanning filter
    disabled s.t. the stripes are more readily apparent.
    '''
    fig = Figure((10, 4))
    canvas = FigureCanvas(fig)
    ax = fig.add_axes([0, 0, 1, 1])
    ax.axis('off')
    plot_radar(ax, 'TOT_stacked_nofilter', 3200, None, [135000, 230000])
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    TOT_bounds, VCD_bounds, THW_bounds = find_quiet_regions()
    ax.vlines(TOT_bounds[0:2], 0, 3200, colors='red', linewidth=3, linestyles='dashed')    
    plot_bounding_box(ax, TOT_bounds, '', linewidth=4)
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)

    canvas.print_figure('../FinalReport/figures/TOT_LO_stripes_d.jpg')

    zoom_bounds = [5000, 9000, 3000, 3200]
    zoom_fig = Figure((2.5, 9))
    zoom_canvas = FigureCanvas(zoom_fig)
    zoom_ax = zoom_fig.add_axes([0, 0, 1, 1])
    zoom_ax.axis('off')
    plot_radar(zoom_ax, 'TOT_stacked_nofilter', 3200, zoom_bounds, [135000, 230000])
    zoom_canvas.print_figure('../FinalReport/figures/TOT_LO_stripes_zoom.jpg')
예제 #2
0
def plot_LO_horiz_stripes():
    '''
    This uses data that has been processed through pik1 but w/ the hanning filter
    disabled s.t. the stripes are more readily apparent.
    '''
    fig = Figure((10, 4))
    canvas = FigureCanvas(fig)
    ax = fig.add_axes([0, 0, 1, 1])
    ax.axis('off')
    plot_radar(ax, 'TOT_stacked_nofilter', 3200, None, [135000, 230000])
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    TOT_bounds, VCD_bounds, THW_bounds = find_quiet_regions()
    ax.vlines(TOT_bounds[0:2],
              0,
              3200,
              colors='red',
              linewidth=3,
              linestyles='dashed')
    plot_bounding_box(ax, TOT_bounds, '', linewidth=4)
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)

    canvas.print_figure('../FinalReport/figures/TOT_LO_stripes_d.jpg')

    zoom_bounds = [5000, 9000, 3000, 3200]
    zoom_fig = Figure((2.5, 9))
    zoom_canvas = FigureCanvas(zoom_fig)
    zoom_ax = zoom_fig.add_axes([0, 0, 1, 1])
    zoom_ax.axis('off')
    plot_radar(zoom_ax, 'TOT_stacked_nofilter', 3200, zoom_bounds,
               [135000, 230000])
    zoom_canvas.print_figure('../FinalReport/figures/TOT_LO_stripes_zoom.jpg')
예제 #3
0
class GEMPlotterDialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        # Set up the user interface from Designer.
        self.ui = Ui_GEMPlotter()
        self.ui.setupUi(self)
        self.modelfile = None
        self.ff = {}  # fragility functions dictionary
        self.fig = Figure()
        self.axes = self.fig.add_subplot(111)
        self.axes.grid(True)
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas.setParent(self)
        self.ui.plotLayout.addWidget(self.canvas)

    @QtCore.pyqtSlot()
    def on_cancelButton_clicked(self):
        self.close()

    @QtCore.pyqtSlot()
    def on_saveButton_clicked(self):
        choices = 'PNG (*.png)|*.png'
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save plot', '', choices))
        self.canvas.print_figure(path)

    @QtCore.pyqtSlot(int)
    def plot_ff(self, taxonomy_idx):
        if taxonomy_idx <= 0:
            return
        self.axes.clear()
        taxonomy = str(self.ui.taxonomyCombo.itemText(taxonomy_idx))
        iml, ys = self.ff[taxonomy]
        for state, y in zip(self.states, ys):
            self.axes.plot(iml['imls'], y, label=state)
        self.axes.legend(loc='upper left')
        self.canvas.draw()
        self.ui.saveButton.setEnabled(True)

    @QtCore.pyqtSlot()
    def on_chooseButton_clicked(self):
        self.modelfile = unicode(QtGui.QFileDialog.getOpenFileName(
            self, 'Select Fragility Model file',
            QtCore.QDir.homePath(),
            'Model files (*.xml)'))
        # TODO: what to do if modelfile is empty?
        # what to do if the file is incorrect?
        self._fillCombo()
        self.ui.taxonomyCombo.currentIndexChanged.connect(self.plot_ff)

    def _fillCombo(self):
        p = iter(FragilityModelParser(self.modelfile))
        kind, self.states = next(p)
        self.ff = dict((taxonomy, (iml, y))
                       for taxonomy, iml, y, no_damage_limit in p)
        self.ui.taxonomyCombo.clear()
        self.ui.taxonomyCombo.addItems(['Taxonomy'] + self.ff.keys())
        self.ui.taxonomyCombo.setEnabled(True)
예제 #4
0
파일: mpl.py 프로젝트: goerz/mgplottools
def write_eps(fig, outfile, dpi=72):
    """
    Write a eps of the given figure, indendent of the pyplot backend.
    However, if the figure was created from pyplot, an existing pyplot backend
    will be permanently changed and may be dysfunctional.
    """
    from matplotlib.backends.backend_ps import FigureCanvasPS as FigureCanvas

    canvas = FigureCanvas(fig)
    canvas.print_figure(outfile, dpi=dpi)
예제 #5
0
def plot_all_utig_data():
    '''
    Plots all UTIG transects on a simple basemap, with transects
    color-coded by season. 
    '''
    fig = Figure((24, 20))
    canvas = FigureCanvas(fig)
    ax = fig.add_axes([0, 0, 1, 1])
    bgs = deva.basemapUtilities.make_background_dict(fig, ax)
    bg = bgs['modis_simple']
    bg.set_background()
    gls = deva.devaUtilities.make_grounding_line_dict()
    deva.devaUtilities.set_grounding_line(ax, gls, 'modis')

    ax.axis('equal')
    ax.set_xlim([-3000000, 3000000])
    ax.set_ylim([-2500000, 2500000])

    ax.tick_params(which='both',
                   bottom=False,
                   top=False,
                   left=False,
                   right=False)
    for side in ['bottom', 'top', 'left', 'right']:
        ax.spines[side].set_visible(False)

    transects = deva.devaUtilities.load_transects(antarctic=True)
    season_lookup = deva.utilities.SeasonLookup()
    for pst, data in transects.iteritems():
        season, _ = season_lookup.get_season(pst)
        if season is None:
            print "No season found for %s" % (pst)
            continue
        elif season in [
                'ASE1', '2001', 'ICP1', 'ICP2', 'ICP3', 'ICP4', 'ICP5'
        ]:
            color = 'k'
            zorder = 3
        elif season in ['ICP6']:
            color = 'darkgrey'
            zorder = 2
        else:
            color = 'lightgrey'
            zorder = 1
        ax.plot(data[:, 1],
                data[:, 2],
                color=color,
                linewidth=1.0,
                zorder=zorder)

    canvas.print_figure('../FinalReport/figures/all_data.png')
예제 #6
0
def plot_data_products():

    # Define all bounds first s.t. we can draw the context boxes on the 
    # dechirped image.

    # The raw bounds are for the full image
    raw_min_sample = 150
    raw_max_sample = 2300
    raw_bounds = [0, 9075, raw_min_sample, raw_max_sample]

    # The filtering needs to zoom in on the surface
    filter_bounds = [1700, 5900, 425, 650]

    # For the SNR improvements of incoherent stacking, look at the layers that just pop out.
    layer_bounds = [7400, 8580, 200, 1750]
    # For filtered, clim = [110000, 195000] and for stacked, clim=[140000, 225000]

    # Zooming in on the crevasses shows speckle nicely
    incoherent_bounds = [2880, 4900, 850, 1700]
    #The clim for this is best is the coherent is [150000, 234000] and incoherent is [160000, 234000]

    # Appropriate color limits depend on the processing used
    raw_clim = [25000, 90000]
    dechirped_clim = [115000, 200000]
    filtered_clim = [115000, 200000]

    # First, generate the raw figure that requires raw data + dechirped data
    # over the full transect.
    raw_shape = (50, 17)
    #raw_shape = (10, 17./5) # This is ugly ... 
    
    # fig_raw = Figure(raw_shape, dpi=150)
    # canvas_raw = FigureCanvas(fig_raw)
    # ax_raw = fig_raw.add_axes([0, 0, 1, 1])
    # ax_raw.axis('off')
    # plot_radar(ax_raw, 'TOT_raw', 3200, raw_bounds, raw_clim)
    # canvas_raw.print_figure('../FinalReport/figures/TOT_raw_full.jpg')


    multiple_bounds = [3050, 5325, 325, 2675]
    fig_multiples = Figure(raw_shape, dpi=150)
    canvas_multiples = FigureCanvas(fig_multiples)
    ax_multiples = fig_multiples.add_axes([0, 0, 1, 1])
    ax_multiples.axis('off')
    plot_radar(ax_multiples, 'TOT_no_blanking', 3200, multiple_bounds, clim=[140000, 230000])
    ax_multiples.text(3950, 900, 'surface multiple', color='red', fontsize=70,
                      horizontalalignment='left', verticalalignment='bottom')
    ax_multiples.text(3950, 2380, 'basal multiple', color='red', fontsize=70,
            horizontalalignment='left', verticalalignment='top')
    canvas_multiples.print_figure('../FinalReport/figures/TOT_multiples.jpg')
예제 #7
0
def plot_before_after():
    
    shape = (36, 27)
    fig_old = Figure(shape, dpi=150)
    canvas_old = FigureCanvas(fig_old)
    ax_old = fig_old.add_axes([0, 0, 1, 1])
    ax_old.axis('off')
    old_filename = WAIS + '/targ/xtra/ICP3/CMP/pik1.RADnh3/TOT/JKB2d/X16a/MagLoResInco2'
    plot_radar(ax_old, old_filename, 3200, clim=[103000, 200000])
    canvas_old.print_figure('../FinalReport/figures/TOT_X16a_old.jpg')

    fig_new = Figure(shape, dpi=150)
    canvas_new = FigureCanvas(fig_new)
    ax_new = fig_new.add_axes([0, 0, 1, 1])
    ax_new.axis('off')
    plot_radar(ax_new, 'TOT_LO', 3200, clim=[136000, 233000])
    canvas_new.print_figure('../FinalReport/figures/TOT_X16a_new.jpg')
예제 #8
0
def plot_before_after():

    shape = (36, 27)
    fig_old = Figure(shape, dpi=150)
    canvas_old = FigureCanvas(fig_old)
    ax_old = fig_old.add_axes([0, 0, 1, 1])
    ax_old.axis('off')
    old_filename = WAIS + '/targ/xtra/ICP3/CMP/pik1.RADnh3/TOT/JKB2d/X16a/MagLoResInco2'
    plot_radar(ax_old, old_filename, 3200, clim=[103000, 200000])
    canvas_old.print_figure('../FinalReport/figures/TOT_X16a_old.jpg')

    fig_new = Figure(shape, dpi=150)
    canvas_new = FigureCanvas(fig_new)
    ax_new = fig_new.add_axes([0, 0, 1, 1])
    ax_new.axis('off')
    plot_radar(ax_new, 'TOT_LO', 3200, clim=[136000, 233000])
    canvas_new.print_figure('../FinalReport/figures/TOT_X16a_new.jpg')
예제 #9
0
def plot_DC():

    shape = (36, 18)

    TOT_bounds = [6000, 9075, 200, 800]

    fig_TOT_ch1 = Figure(shape, dpi=150)
    canvas_TOT_ch1 = FigureCanvas(fig_TOT_ch1)
    ax_TOT_ch1 = fig_TOT_ch1.add_axes([0, 0, 1, 1])
    ax_TOT_ch1.axis('off')
    old_filename = WAIS + '/targ/xtra/ICP3/CMP/pik1.RADnh3/TOT/JKB2d/X16a/MagLoResInco1'
    plot_radar(ax_TOT_ch1,
               old_filename,
               3200,
               bounds=TOT_bounds,
               clim=[80000, 180000])
    canvas_TOT_ch1.print_figure('../FinalReport/figures/TOT_ch1_DC.jpg')

    fig_TOT_ch2 = Figure(shape, dpi=150)
    canvas_TOT_ch2 = FigureCanvas(fig_TOT_ch2)
    ax_TOT_ch2 = fig_TOT_ch2.add_axes([0, 0, 1, 1])
    ax_TOT_ch2.axis('off')
    plot_radar(ax_TOT_ch2,
               'TOT_no_blanking',
               3200,
               bounds=TOT_bounds,
               clim=[130000, 230000])
    canvas_TOT_ch2.print_figure('../FinalReport/figures/TOT_ch2_DC.jpg')

    VCD_bounds = [9600, 10470, 200, 800]

    fig_VCD_ch1 = Figure(shape, dpi=150)
    canvas_VCD_ch1 = FigureCanvas(fig_VCD_ch1)
    ax_VCD_ch1 = fig_VCD_ch1.add_axes([0, 0, 1, 1])
    ax_VCD_ch1.axis('off')
    old_filename = WAIS + '/targ/xtra/ICP4/CMP/pik1.RADnh3/VCD/JKB2g/DVD01a/MagLoResInco1'
    plot_radar(ax_VCD_ch1,
               old_filename,
               3200,
               bounds=VCD_bounds,
               clim=[80000, 180000])
    canvas_VCD_ch1.print_figure('../FinalReport/figures/VCD_ch1_DC.jpg')

    fig_VCD_ch2 = Figure(shape, dpi=150)
    canvas_VCD_ch2 = FigureCanvas(fig_VCD_ch2)
    ax_VCD_ch2 = fig_VCD_ch2.add_axes([0, 0, 1, 1])
    ax_VCD_ch2.axis('off')
    plot_radar(ax_VCD_ch2,
               'VCD_no_blanking',
               3200,
               bounds=VCD_bounds,
               clim=[140000, 230000])
    canvas_VCD_ch2.print_figure('../FinalReport/figures/VCD_ch2_DC.jpg')
예제 #10
0
def plot_all_utig_data():
    '''
    Plots all UTIG transects on a simple basemap, with transects
    color-coded by season. 
    '''
    fig = Figure((24, 20))
    canvas = FigureCanvas(fig)
    ax = fig.add_axes([0,0,1,1])
    bgs = deva.basemapUtilities.make_background_dict(fig, ax)
    bg = bgs['modis_simple']
    bg.set_background()
    gls = deva.devaUtilities.make_grounding_line_dict()
    deva.devaUtilities.set_grounding_line(ax, gls, 'modis')

    ax.axis('equal')
    ax.set_xlim([-3000000, 3000000])
    ax.set_ylim([-2500000, 2500000])

    ax.tick_params(which='both', bottom=False, top=False, left=False, right=False)
    for side in ['bottom', 'top', 'left', 'right']:
        ax.spines[side].set_visible(False)

    transects = deva.devaUtilities.load_transects(antarctic=True)
    season_lookup = deva.utilities.SeasonLookup()
    for pst, data in transects.iteritems():
        season,_ = season_lookup.get_season(pst)
        if season is None:
            print "No season found for %s" % (pst)
            continue
        elif season in ['ASE1', '2001', 'ICP1', 'ICP2', 'ICP3', 'ICP4', 'ICP5']:
            color = 'k'
            zorder = 3
        elif season in ['ICP6']:
            color = 'darkgrey'
            zorder = 2
        else:
            color = 'lightgrey'
            zorder = 1
        ax.plot(data[:,1], data[:,2], color=color, linewidth=1.0, zorder=zorder)
    
    canvas.print_figure('../FinalReport/figures/all_data.png')
예제 #11
0
def plot_quiet_regions():
    # Plot the region that the noise was calculated from...
    # For TOT...
    TOT_bounds, VCD_bounds, THW_bounds = find_quiet_regions()

    # TOT/JKB2d/X16a gives: 
    # mag = 32809.224658469, phs = -0.90421798501485484
    # VCD/JKB2g/DVD01a gives:
    # mag = 15720.217174332585, phs = -0.98350090576267946
    # THW/SJB2/DRP02a gives:
    # 26158.900202734963, phs = 1.6808311318828895
    
    TOT_fig = Figure((10, 8))
    TOT_canvas = FigureCanvas(TOT_fig)
    TOT_ax = TOT_fig.add_axes([0, 0, 1, 1])
    TOT_ax.axis('off')
    plot_radar(TOT_ax, 'TOT_LO', 3200, None, [135000, 234000])
    xlim = TOT_ax.get_xlim()
    ylim = TOT_ax.get_ylim()
    TOT_ax.vlines(TOT_bounds[0:2], 0, 3200, colors='red', linewidth=3, linestyles='dashed')
    plot_bounding_box(TOT_ax, TOT_bounds, '', linewidth=4)
    TOT_ax.set_xlim(xlim)
    TOT_ax.set_ylim(ylim)
    TOT_canvas.print_figure('../FinalReport/figures/TOT_quiet_region.jpg')

    VCD_fig = Figure((10, 8))
    VCD_canvas = FigureCanvas(VCD_fig)
    VCD_ax = VCD_fig.add_axes([0, 0, 1, 1])
    VCD_ax.axis('off')
    plot_radar(VCD_ax, 'VCD_LO', 3200, None, [135000, 234000])
    xlim = VCD_ax.get_xlim()
    ylim = VCD_ax.get_ylim()
    VCD_ax.vlines(VCD_bounds[0:2], 0, 3200, colors='red', linewidth=3, linestyles='dashed')
    plot_bounding_box(VCD_ax, VCD_bounds, '', linewidth=4)
    VCD_ax.set_xlim(xlim)
    VCD_ax.set_ylim(ylim)
    VCD_canvas.print_figure('../FinalReport/figures/VCD_quiet_region.jpg')

    THW_fig = Figure((10, 8))
    THW_canvas = FigureCanvas(THW_fig)
    THW_ax = THW_fig.add_axes([0, 0, 1, 1])
    THW_ax.axis('off')
    plot_radar(THW_ax, 'THW_LO', 3200, None, [135000, 234000])
    xlim = THW_ax.get_xlim()
    ylim = THW_ax.get_ylim()
    THW_ax.vlines(THW_bounds[0:2], 0, 3200, colors='red', linewidth=3, linestyles='dashed')
    plot_bounding_box(THW_ax, THW_bounds, '', linewidth=4)
    THW_ax.set_xlim(xlim)
    THW_ax.set_ylim(ylim)
    THW_canvas.print_figure('../FinalReport/figures/THW_quiet_region.jpg')
예제 #12
0
def plot_DC():    

    shape = (36, 18)

    TOT_bounds = [6000, 9075, 200, 800]
    
    fig_TOT_ch1 = Figure(shape, dpi=150)
    canvas_TOT_ch1 = FigureCanvas(fig_TOT_ch1)
    ax_TOT_ch1 = fig_TOT_ch1.add_axes([0, 0, 1, 1])
    ax_TOT_ch1.axis('off')
    old_filename = WAIS + '/targ/xtra/ICP3/CMP/pik1.RADnh3/TOT/JKB2d/X16a/MagLoResInco1'
    plot_radar(ax_TOT_ch1, old_filename, 3200, bounds=TOT_bounds, clim=[80000, 180000])
    canvas_TOT_ch1.print_figure('../FinalReport/figures/TOT_ch1_DC.jpg')

    fig_TOT_ch2 = Figure(shape, dpi=150)
    canvas_TOT_ch2 = FigureCanvas(fig_TOT_ch2)
    ax_TOT_ch2 = fig_TOT_ch2.add_axes([0, 0, 1, 1])
    ax_TOT_ch2.axis('off')
    plot_radar(ax_TOT_ch2, 'TOT_no_blanking', 3200, bounds=TOT_bounds, clim=[130000, 230000])
    canvas_TOT_ch2.print_figure('../FinalReport/figures/TOT_ch2_DC.jpg')

    VCD_bounds = [9600, 10470, 200, 800]
    
    fig_VCD_ch1 = Figure(shape, dpi=150)
    canvas_VCD_ch1 = FigureCanvas(fig_VCD_ch1)
    ax_VCD_ch1 = fig_VCD_ch1.add_axes([0, 0, 1, 1])
    ax_VCD_ch1.axis('off')
    old_filename = WAIS + '/targ/xtra/ICP4/CMP/pik1.RADnh3/VCD/JKB2g/DVD01a/MagLoResInco1'
    plot_radar(ax_VCD_ch1, old_filename, 3200, bounds=VCD_bounds, clim=[80000, 180000])
    canvas_VCD_ch1.print_figure('../FinalReport/figures/VCD_ch1_DC.jpg')

    fig_VCD_ch2 = Figure(shape, dpi=150)
    canvas_VCD_ch2 = FigureCanvas(fig_VCD_ch2)
    ax_VCD_ch2 = fig_VCD_ch2.add_axes([0, 0, 1, 1])
    ax_VCD_ch2.axis('off')
    plot_radar(ax_VCD_ch2, 'VCD_no_blanking', 3200, bounds=VCD_bounds, clim=[140000, 230000])
    canvas_VCD_ch2.print_figure('../FinalReport/figures/VCD_ch2_DC.jpg')    
예제 #13
0
class PlotDisplay(Component):
    '''
    Class to create a display plot, using data and a key for plot type.
    '''

    def __init__(self, data, ydata=None, plot_type=None, 
                 title=None, xlabel=None, ylabel=None,
                 name="PlotDisplay", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        data : data array
            The data to be plotted.
        [Optional]
        plot_type : str
            Type of plot to produce (e.g. plot, barplot, etc).
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        Notes
        -----
        This class records the selected button and passes the
        change value back to variable.
        '''
        super(PlotDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.data = data
        self.ydata = ydata
        self.plot_type = plot_type

        # Set plot title and colorbar units to defaults
        self.title = title
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.units = None
        self.limits = None

        # Find the PyArt colormap names
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Create the plot
        self._update_plot()
##        self.NewRadar(None, None, True)

        self.show()

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(4)

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add buttons along display for user control
        self.addButtons()
        self.setUILayout()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    ##################################
    # User display interface methods #
    ##################################
    def addButtons(self):
        '''Add a series of buttons for user control over display.'''
        # Create the Display controls
        self._add_displayBoxUI()

    def setUILayout(self):
        '''Setup the button/display UI layout.'''
        self.layout.addWidget(self.dispButton, 0, 1)

    #############################
    # Functionality methods #
    #############################

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(self.limits, self.cmap, self.name)
        if change == 1:
            self.cmap = cmap
            self.limits = limits
            self._update_plot()

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog(self.title, "Plot Title", "Title:")
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog(self.units, "Plot Units", "Units:")
        if entry is True:
            self.units = val
            self._update_plot()

    def _add_cmaps_to_button(self):
        '''Add a menu to change colormap used for plot.'''
        for cm_name in self.cm_names:
            cmapAction = self.dispCmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap" % cm_name)
            cmapAction.triggered[()].connect(
                lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
            self.dispCmap.setMenu(self.dispCmapmenu)

    def _add_displayBoxUI(self):
        '''Create the Display Options Button menu.'''
        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = dispmenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
        dispTitle = dispmenu.addAction("Change Title")
        dispTitle.setToolTip("Change plot title")
        dispUnit = dispmenu.addAction("Change Units")
        dispUnit.setToolTip("Change units string")
#        toolZoomPan = dispmenu.addAction("Zoom/Pan")
        self.dispCmap = dispmenu.addAction("Change Colormap")
        self.dispCmapmenu = QtGui.QMenu("Change Cmap")
        self.dispCmapmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        dispSaveFile = dispmenu.addAction("Save Image")
        dispSaveFile.setShortcut("Ctrl+S")
        dispSaveFile.setStatusTip("Save Image using dialog")
        self.dispHelp = dispmenu.addAction("Help")

        dispLimits.triggered[()].connect(self._open_LimsDialog)
        dispTitle.triggered[()].connect(self._title_input)
        dispUnit.triggered[()].connect(self._units_input)
#        toolZoomPan.triggered[()].connect(self.toolZoomPanCmd)
        dispSaveFile.triggered[()].connect(self._savefile)
        self.dispHelp.triggered[()].connect(self.displayHelp)

        self._add_cmaps_to_button()
        self.dispButton.setMenu(dispmenu)

    def displayHelp(self):
        text = "<b>Using the Simple Plot Feature</b><br><br>"
        text += "<i>Purpose</i>:<br>"
        text += "Display a plot.<br><br>"
        text += "The limits dialog is a common format that allows the user change:<br>"
        text += "<i>X and Y limits<br>"
        text += "Data limits</i><br>"
        text += "However, not all plots take each argument.<br>"
        text += "For example, a simple line plot has no data min/max data value.<br>"

        common.ShowLongText(text)

    ########################
    # Selectionion methods #
    ########################

#     def _create_plot(self):
#         '''
#         Create a plot
#         '''
#         # test for None
#         if self.Vradar.value is None:
#             self.fieldBox.clear()
#             self.tiltBox.clear()
#             return
# 
#         # Get the tilt angles
#         self.rTilts = self.Vradar.value.sweep_number['data'][:]
#         # Get field names
#         self.fieldnames = self.Vradar.value.fields.keys()
# 
#         # Check the file type and initialize limts
#         self._check_file_type()
# 
#         # Update field and tilt MenuBox
#         self._fillTiltBox()
#         self._fillFieldBox()
# 
#         self.units = None
#         if strong:
#             self._update_plot()

#     def NewLims(self, variable, value, strong):
#         '''
#         Slot for 'ValueChanged' signal of
#         :py:class:`Vlims <artview.core.core.Variable>`.
# 
#         This will:
# 
#         * If strong update: update axes
#         '''
#         if strong:
#             self._update_axes()

#     def NewCmap(self, variable, value, strong):
#         '''
#         Slot for 'ValueChanged' signal of
#         :py:class:`Vcmap <artview.core.core.Variable>`.
# 
#         This will:
# 
#         * If strong update: update plot
#         '''
#         if strong and self.Vradar.value is not None:
#             self._update_plot()

    def cmapSelectCmd(self, cm_name):
        '''Captures colormap selection and redraws.'''
        self.cmap['cmap'] = cm_name
#        self.Vcmap.value['cmap'] = cm_name
#        self.Vcmap.change(self.Vcmap.value)

#    def toolZoomPanCmd(self):
#        '''Creates and connects to a Zoom/Pan instance.'''
#        from .tools import ZoomPan
#        scale = 1.1
#        self.tools['zoompan'] = ZoomPan(
#            self.limits, self.ax,
#            base_scale=scale, parent=self.parent)
#        self.tools['zoompan'].connect()

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 5
        self.YSIZE = 5
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])

#    def _update_fig_ax(self):
#        '''Set the figure and axis to plot.'''
#        if self.plot_type in ("radarAirborne", "radarRhi"):
#            self.YSIZE = 5
#        else:
#            self.YSIZE = 8
#        xwidth = 0.7
#        yheight = 0.7 * float(self.YSIZE) / float(self.XSIZE)
#        self.ax.set_position([0.2, 0.55-0.5*yheight, xwidth, yheight])
#        self.cax.set_position([0.2, 0.10, xwidth, 0.02])
#        self._update_axes()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 4, 3)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''

        # Create the plot with PyArt PlotDisplay
        self.ax.cla()  # Clear the plot axes

        # Reset to default title if user entered nothing w/ Title button
        if self.title == '':
            title = None
        else:
            title = self.title

        colorbar_flag=False

        self.cmap = {'vmin': self.data.min(), 'vmax': self.data.max(),
                     'cmap': 'pyart_RefDiff'}

        if self.plot_type == "hist":
            self.plot = self.ax.hist(self.data, bins=25,
                range = (self.cmap['vmin'], self.cmap['vmax']),
                figure=self.fig)
            self.ax.set_ylabel("Counts")
            if self.xlabel:
                self.ax.set_xlabel(self.xlabel)

        elif self.plot_type == "hist2d":
            # Check that y data was provided
            if self.ydata:
                y = self.ydata
            # Create Plot
            self.plot = self.ax.hist2d(self.data, y,
                bins=[25, 20],
                range=[[self.cmap['vmin'], self.cmap['vmax']],
                       [y.min(), y.max()]],
                cmap=self.cm_name,
                figure=self.fig)
            colorbar_flag=True

        elif self.plot_type == "plot":
            # Check that y data was provided
            if self.ydata:
                y = self.ydata
            # Create Plot
            self.plot = self.ax.plot(self.data, y,
                figure=self.fig)

        # Set the axis labels if arguments passed
        if self.xlabel:
            self.ax.set_xlabel(self.xlabel)
        if self.ylabel:
            self.ax.set_ylabel(self.ylabel)

        # If limits exists, update the axes otherwise retrieve
        if self.limits:
            self._update_axes()
        else:
            self._get_axes_limits()

        # Set the title if passed
        if title is not None:
            self.ax.set_title(title)

        # If the colorbar flag is thrown, create it
        if colorbar_flag:
            # Clear the colorbar axes
            self.cax.cla()
            self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
            norm = mlabNormalize(vmin=self.cmap['vmin'],
                                 vmax=self.cmap['vmax'])
            self.cbar = mlabColorbarBase(self.cax, cmap=self.cm_name,
                                         norm=norm, orientation='horizontal')
            # colorbar - use specified units or default depending on
            # what has or has not been entered
            if self.units is None or self.units == '':
                self.units = ''
            self.cbar.set_label(self.units)

        self.canvas.draw()

    def _update_axes(self):
        '''Change the Plot Axes.'''
        self.ax.set_xlim(self.limits['xmin'], self.limits['xmax'])
        self.ax.set_ylim(self.limits['ymin'], self.limits['ymax'])
        self.ax.figure.canvas.draw()

    def _get_axes_limits(self):
        '''Get the axes limits'''
        xlim = self.ax.get_xlim()
        ylim = self.ax.get_ylim()
        self.limits = {}
        self.limits['xmin'] = xlim[0]
        self.limits['xmax'] = xlim[1]
        self.limits['ymin'] = ylim[0]
        self.limits['ymax'] = ylim[1]

    ########################
    # Image save methods #
    ########################

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', ' ', file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)
예제 #14
0
class MainApp(QtGui.QMainWindow, mainMenu.Ui_MainWindow,
orbitsMenu.Ui_orbitsMenu, imagesMenu.Ui_imagesMenu, mcMenu.Ui_Frame):

    def __init__(self, parent = None):

        QtGui.QMainWindow.__init__(self, parent)
        # se crea la ventana principal
        self.ventana = mainMenu.Ui_MainWindow()
        self.ventana.setupUi(self)
        ## imagen principal
        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        ## se le agrega a la figura la accion movimiento del mouse sobre ella
        self.figure.canvas.mpl_connect("motion_notify_event", self.mouse_move)
        self.main_frame = self.ventana.verticalLayout.addWidget(self.canvas)
        ## barra de edicion de grafica
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        self.ventana.verticalLayout.addWidget(self.mpl_toolbar)
        ## imagen zoom
        self.figure2 = plt.figure()
        self.canvas2 = FigureCanvas(self.figure2)
        self.main_frame2 = self.ventana.verticalLayout_3.addWidget(self.canvas2)

        ### acciones bar menu
        self.connect(self.ventana.action_Quit, QtCore.SIGNAL("triggered()"),
            QtCore.SLOT('close()'))
        #self.connect(self.ventana.action_Abrir,QtCore.SIGNAL("triggered()"),self.openFile)
        #self.connect(self.ventana.action_guardar,QtCore.SIGNAL("triggered()"),self.guardarPlot)
        self.connect(self.ventana.action_About,
        QtCore.SIGNAL("triggered()"), self.about)
        self.connect(self.ventana.actionMassiveCalc,
        QtCore.SIGNAL("triggered()"), self.showMC)
        # acciones combobox
        self.connect(self.ventana.comboBox,
        QtCore.SIGNAL("currentIndexChanged(int)"), self.putMenu)
        #### por defecto esta seleccionado orbitsMenu
        ###self.showOrbitsMenu()

    def putMenu(self):

        valorCB = str(self.ventana.comboBox.currentText())
        if (valorCB == "SAC-D/Aquarius"):
            self.showOrbitsMenu()
        elif (valorCB == "None"):
            self.removeButtons()
        else:
            self.showImagesMenu()

    ###----------------------------Orbits Menu---------------------------------
    def showOrbitsMenu(self):
        """ Función que carga el menú orbitas

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se borran las imagenes previas, textEdit y otros
        self.clear()
        # se elimina elementos creados previos si es que existen
        self.removeButtons()
        # se crea un objeto QWidget
        orbitsMenuQw = QtGui.QWidget()
        # se crea una instancia de la clase que crea el menu
        self.orbitsMenu = orbitsMenu.Ui_orbitsMenu()
        # se llama a la funcion que inserta los elementos
        self.orbitsMenu.setupUi(orbitsMenuQw)
        # se inserta el menu en la ventana principal
        self.ventana.verticalLayout_2.addWidget(orbitsMenuQw)
        # acciones de los elementos de orbitsMenu
        self.orbitsMenu.pushButton.clicked.connect(self.openTargz)
        # si se selecciona el nivel, se cargan los productos/bandas
        self.orbitsMenu.comboBox.currentIndexChanged.connect(self.putProductBand)
        self.orbitsMenu.comboBox_2.currentIndexChanged.connect(self.putMaps)
        self.orbitsMenu.comboBox_3.currentIndexChanged.connect(self.putColorbars)
        self.orbitsMenu.comboBox_4.currentIndexChanged.connect(self.activateButtonGraph)
        self.orbitsMenu.pushButton_2.clicked.connect(self.graph)
        self.orbitsMenu.pushButton_3.clicked.connect(self.savePlot)

    def openTargz(self):
        """ Abre archivos tar.gz pertenecientes a SAC-D/Aquarius (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se borran las imagenes previas, textEdit y otros
        self.clear()
        # se desactiva el boton guardar
        self.orbitsMenu.pushButton_3.setEnabled(False)
        # lista archivos seleccionados (self.listFiles es una QStringList)
        self.listFiles = QtGui.QFileDialog.getOpenFileNames(self,
             "Select file/s tar.gz")
        # print self.listFiles.isEmpty()
        if (self.listFiles.isEmpty() is False):
            #self.ventana.textEdit.setText("# Opened Folder # \n"+self.listFiles + "\n")
            #listFile = os.listdir(self.folder)
            numFiles = self.listFiles.count()
            #print numFiles
            # se valida la existencia de archivos tar.gz
            flag = 0
            for i in range(0, numFiles):
                if str(self.listFiles[i]).find(".tar.gz") != -1:
                    flag = 1
            if (flag != 1):
                reply = QtGui.QMessageBox.critical(self, 'Message',
                "tar.gz files from SAC-D/Aquarius mission")
                self.listFiles = QtGui.QFileDialog.getOpenFileNames(self,
                "Select file/s tar.gz")
            ## se cargan los niveles
            self.putLevels()
        self.activateButtonGraph()

    def putLevels(self):
        """ Función carga los niveles de procesamiento (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.orbitsMenu.comboBox.clear()
        self.orbitsMenu.comboBox.addItem("None")
        self.orbitsMenu.comboBox.addItem("L1B")
        self.orbitsMenu.comboBox.addItem("L2")

    def putProductBand(self):
        """ Carga bandas/productos según nivel de procesamiento (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se obtiene el valor del combobox  de nivel de procesamiento
        text = self.orbitsMenu.comboBox.currentText()
        # se borra el combobox de las bandas
        self.orbitsMenu.comboBox_2.clear()
        # si se selecciona None
        if (text == "None"):
            self.orbitsMenu.comboBox_2.addItem("None")
        # si es L1B
        if (text == "L1B"):
            # se cargan los productos de nivel L1-B
            self.orbitsMenu.comboBox_2.addItem("None")
            self.orbitsMenu.comboBox_2.addItem("ka_h_antenna_temperature")
            self.orbitsMenu.comboBox_2.addItem("ka_v_antenna_temperature")
            self.orbitsMenu.comboBox_2.addItem("ka_n45_antenna_temperature")
            self.orbitsMenu.comboBox_2.addItem("ka_p45_antenna_temperature")
        if (text == "L2"):
            # se cargan los productos de nivel L2
            self.orbitsMenu.comboBox_2.addItem("None")
            self.orbitsMenu.comboBox_2.addItem("columnar_water_vapor")
            self.orbitsMenu.comboBox_2.addItem("wind_speed")

    def putMaps(self):
        """ Carga tipos de mapa donde se puede graficar (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se obtiene el valor del combobox banda/producto
        text = self.orbitsMenu.comboBox_2.currentText()
        # se borra el combobox de las bandas
        self.orbitsMenu.comboBox_3.clear()
        # si se selecciono anteriormente None
        if (text == "None"):
            self.orbitsMenu.comboBox_3.addItem("None")
        else:
            self.orbitsMenu.comboBox_3.addItem("None")
            self.orbitsMenu.comboBox_3.addItem("robin")
            self.orbitsMenu.comboBox_3.addItem("mill")
            self.orbitsMenu.comboBox_3.addItem("kav7")

    def putColorbars(self):
        ## coloca los tipos de color bar
        """ Función que carga las diferentes escalas de colores (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se obtiene el valor del combobox banda/producto
        text = self.orbitsMenu.comboBox_3.currentText()
        # se borra el combobox de las bandas
        self.orbitsMenu.comboBox_4.clear()
        # si se selecciono anteriormente None
        if (text == "None"):
            self.orbitsMenu.comboBox_4.addItem("None")
        else:
            self.orbitsMenu.comboBox_4.addItem("None")
            self.orbitsMenu.comboBox_4.addItem("hot")
            self.orbitsMenu.comboBox_4.addItem("jet")
            self.orbitsMenu.comboBox_4.addItem("summer")
            self.orbitsMenu.comboBox_4.addItem("winter")

    def activateButtonGraph(self):
        """ Función que activa el boton graficar (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se obtiene el valor del combobox banda/producto
        text = self.orbitsMenu.comboBox_4.currentText()
        # si se selecciono None
        if (text == "None"):
            self.orbitsMenu.pushButton_2.setEnabled(False)
        if ((self.listFiles.isEmpty() is False) and (text != "None")):
            self.orbitsMenu.pushButton_2.setEnabled(True)

    def graph(self):
        """ Función que grafica los archivos tar.gz seleccionados (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.ventana.textEdit.append("Iniciando...")
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()
        # se borran las imagenes previas
        self.clear1()
        # se obtienen los valores seleccionados en OrbitsMenu
        listFiles = self.listFiles
        level = str(self.orbitsMenu.comboBox.currentText())
        nameProduct = str(self.orbitsMenu.comboBox_2.currentText())
        typeMap = str(self.orbitsMenu.comboBox_3.currentText())
        nameCB = str(self.orbitsMenu.comboBox_4.currentText())
        #print "path: " + path
        #print "level: " + level
        #print "nameProduct: " + nameProduct
        #print "nameCB: " + nameCB
        #print "typeMap: " + typeMap
        # se extraen los tar.gz en un archivo temporal
        pathHDF = processing.extractFiles(listFiles, self.ventana.textEdit)
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()
        #### muy importante ####
        # como utilizo plt para graficar solo puedo tener un solo objeto figure
        plt.close(self.figure2)
        # se genera el mapa
        mapa = visualization.generateMap(typeMap, level, self.ventana.textEdit)
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()
        # se obtiene la imagen
        visualization.graphSACDProduct(plt, self.figure, pathHDF, level, nameProduct, nameCB, mapa, self.ventana.textEdit)
        # para hacer mas pequenios los margenes
        self.figure.tight_layout()
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()
        # se elimina la carpeta temporal de los archivos descomprimidos
        processing.eliminateTmp(pathHDF, self.ventana.textEdit)
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()
        # se grafica
        self.figure.subplots_adjust(left = 0.05, right = 0.95, bottom = 0.05, top = 0.95)
        self.canvas.draw()
        # se activa el boton guardar grafica
        self.orbitsMenu.pushButton_3.setEnabled(True)
        return

    def savePlot(self):
        """ Guarda grafico creado en formato png (menú orbitas)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        file_choices = "PNG (*.png)|*.png"
        self.dpi = 100
        path = unicode(QtGui.QFileDialog.getSaveFileName(self,'Save file', '',file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
        return

    ###-------------------------Fin Orbits Menu--------------------------------

    ###----------------------------Images Menu---------------------------------
    def showImagesMenu(self):
        """ Función que carga el menú imágenes

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se borran las imagenes previas, textEdit y otros
        self.clear()
        ## se elimina elementos creados previos si es que existen
        self.removeButtons()
        # se crea un objeto QWidget
        imagesMenuQw = QtGui.QWidget()
        # se crea una instancia de la clase que crea el menu
        self.imagesMenu = imagesMenu.Ui_imagesMenu()
        # se llama a la funcion que inserta los elementos
        self.imagesMenu.setupUi(imagesMenuQw)
        # se inserta el menu en la ventana principal
        self.ventana.verticalLayout_2.addWidget(imagesMenuQw)
        # acciones de los elementos de imagesMenu
        self.imagesMenu.pushButton.clicked.connect(self.openFile)
        ## si se selecciona el mapa de colores se cargan las bandas
        self.imagesMenu.comboBox.currentIndexChanged.connect(self.putImage)
        self.imagesMenu.comboBox_2.currentIndexChanged.connect(self.putImage)
        self.imagesMenu.radioButton.clicked.connect(self.changeLatLon)
        self.imagesMenu.radioButton_2.clicked.connect(self.changeRowCol)
        # cuando se hace click en el boton extract
        self.imagesMenu.pushButton_2.clicked.connect(self.extract)

    def openFile(self):
        """ Abre imágenes GeoTiff (menú imagenes)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # se borran las imagenes previas, textEdit y otros
        self.clear()
        # se desactiva el boton guardar
        #self.orbitsMenu.pushButton_3.setEnabled(False)
        #self.putTextComboBox()
        self.filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File')
        if (self.filename != ""):
            self.ventana.textEdit.setText("# Opened File # \n" + self.filename)
            # carga imagen con rasterIO /GDAL compatible
            self.file_pointer = rasterIO.opengdalraster(str(self.filename))
            driver, self.XSize, self.YSize, self.NBand, proj_wkt, geo = rasterIO.readrastermeta(self.file_pointer)
            self.lon0, self.lat0 = geo[0], geo[3]
            self.dlon, self.dlat = geo[1], geo[5]
            # rango de latitud y longitud
            max_lat = self.lat0 + self.YSize * self.dlat
            max_lon = self.lon0 + self.XSize * self.dlon
            # Show and Log figure metadata
            sms = "\n+ Metadata \n    " + proj_wkt + "\n"
            sms += "    - Size = " + str(self.YSize) + "," + str(self.XSize) + "\n"
            sms += "    - Delta latitude = " + str(self.dlat) + "\n    - Delta longitude = " + str(self.dlon) + "\n"
            sms += "    - Latitude limits: \n"
            sms += "        from = " + str(self.lat0) + "\n"
            sms += "        to   = " + str(max_lat) + "\n"
            sms += "    - Longitude limits: \n"
            sms += "        from = " + str(self.lon0) + "\n"
            sms += "        to   = " + str(max_lon) + "\n"
            self.ventana.textEdit.append(sms)
            # se muestra la imagen con el mapa de colores y la banda 1
            self.putImage()
            # actualiza el combobox de bandas
            self.putBand()
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()

    def putBand(self):
        """ Función carga las bandas de la imagen (menú imagenes)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        colorMap = self.imagesMenu.comboBox.currentText()
        # se borra el combobox de las bandas
        self.imagesMenu.comboBox_2.clear()

        # se obtiene la cantidad de bandas de la imagen seleccionada
        bands = [str(b) for b in range(1, self.NBand + 1)]
        self.imagesMenu.comboBox_2.addItems(bands)

    def putImage(self):
        """ Función que muestra la imagen requerida (menú imagenes)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.clear1()
        # se obtiene el colormap seleccionado
        colorMap = str(self.imagesMenu.comboBox.currentText())
        if (colorMap == " "):
            colorMap = "gist_earth"
        # se obtiene la banda seleccionada
        if (self.imagesMenu.comboBox_2.currentText() == ''):
            band = 1
        else:
            band = int(self.imagesMenu.comboBox_2.currentText())
        self.data = rasterIO.readrasterband(self.file_pointer, band)
        self.data = self.data.astype(np.float32)
        self.ax = self.figure.add_subplot(111)
        colorValue = eval("cm." + colorMap)
        image = self.ax.imshow(self.data, cmap=colorValue)
        # se inserta la barra de colores
        # el segundo parametro es el tamano de la barra de colores
        self.figure.colorbar(image, pad=0.01)
        # para hacer mas pequenios los margenes
        self.figure.tight_layout()
        # se actualiza la interfaz para mostrar las acciones en el textEdit
        QtGui.QApplication.processEvents()
        # se grafica
        self.canvas.draw()
        # se activa el boton extract
        self.imagesMenu.pushButton_2.setEnabled(True)

    def changeRowCol(self):
        """ Intercambia los nombres de los combobox (menú imagenes)

        Cambia label Latitude/Longitude por Row/column

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.imagesMenu.label_4.setText('Row')
        self.imagesMenu.label_5.setText('Column')

    def changeLatLon(self):
        """ Intercambia los nombres de los combobox (menú imagenes)

        Cambia label Row/column por Latitude/Longitude

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.imagesMenu.label_4.setText('Latitude')
        self.imagesMenu.label_5.setText('Longitude')

    def extract(self):
        """ Extrae el valor de un pixel de la imagen (menú imagenes)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # Get the value from image
        if (self.imagesMenu.radioButton.isChecked()):
            # esta seleccionada "Lat/Lon"
            lat = float(self.imagesMenu.lineEdit.text())
            lon = float(self.imagesMenu.lineEdit_2.text())
            ## Image indexes
            row,col = module.getRowCol(lat,lon,self.lat0, self.lon0, self.dlat, self.dlon)

        else:
            row = float(self.imagesMenu.lineEdit.text())
            col = float(self.imagesMenu.lineEdit_2.text())
            ## Only to be logged
            lat, lon = module.getLatLon(row,col,self.lat0, self.lon0, self.dlat, self.dlon)
        ## Format the info to be logged
        sms = "\n+ Extract operation \n"
        sms += "     Lat = " + str(lat) + "\n"
        sms += "     Lon = " + str(lon) + "\n"
        sms += "     Row = " + str(row) + "\n"
        sms += "     Col = " + str(col) + "\n"
        self.ventana.textEdit.append(sms)
        if (self.YSize < row or row < 0) or (self.XSize < col or col < 0):
            # if row or col are out of bounds
            self.ventana.textEdit.append("\n Error: Row or column out of bouds")
        else:
            self.imagesMenu.lineEdit_3.setText(str(self.data[row][col]))
            self.ventana.textEdit.append("     Extracted value = " + str(self.data[row][col]))

    ###------------------------Fin Images Menu---------------------------------
    ###------------------------------------------------------------------------
    ###------------------------MassiveCalc-------------------------------------

    def showMC(self):
        """ Función que muestra la ventana de calculos masivos

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        # primero se crea el objeto frame
        self.frame = QtGui.QFrame()
        self.frame.setWindowTitle("Titi")
        # se instancia la clase de la ventana calculos masivos
        titi_calcs_app.CalcsApp(self.frame)
        # se le fija el tamaño a la ventana y se quita el resize
        width = 900
        height = 600
        self.frame.setFixedSize(width, height)
        self.frame.show()
        return

    ###------------------------Fin massiveCalc---------------------------------
    ###------------------------------------------------------------------------
    ###------------------------Funciones generales-----------------------------

    def removeButtons(self):
        """ Elimina widgets agregados dinamicamente (menú orbitas o imágenes)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        for cnt in range(self.ventana.verticalLayout_2.count()):
            value = str(self.ventana.verticalLayout_2.itemAt(cnt))
            #print value
            if (value.find("QWidgetItem") != -1):
                self.ventana.verticalLayout_2.itemAt(cnt).widget().close()

    def mouse_move(self, event):
        """ Captura posición del mouse sobre imagen (menú imágenes)

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        valorCB = str(self.ventana.comboBox.currentText())
        if not event.inaxes:
            return
        if (valorCB != "SAC-D/Aquarius"):
            # solo si se encuentra en imagesMenu
            #if (self.ventana.verticalLayout_3.count() == 0):
                ## no se agrego la figura de zoom aun
                ## entonces se agrega el figure
            x, y = event.xdata, event.ydata
            #self.ventana.label_2.setText(str(x) + " " + str(y))
            if (0 <= x <= self.XSize) and (0 <= y <= self.YSize):
                # se obtiene el colormap seleccionado
                colorMap = str(self.imagesMenu.comboBox.currentText())
                colorValue = eval("cm." + colorMap)
                ## Load small zoom
                self.figure2.clear()
                self.ax2 = self.figure2.add_subplot(111)
                image2 = self.ax2.imshow(self.data[y-8:y+8,x-8:x+8], cmap = colorValue)
                self.canvas2.draw()
            # statusBar
            col, row = int(x), int(y)
            lat, lon = module.getLatLon(row,col, self.lat0, self.lon0, self.dlat, self.dlon)
            sms = "Row,Col = [" + str(row) + "," + str(col) + "]     |     Lat,Lon =  [" + str(lat) + "," + str(lon) + "]"
            sms += "    |    Value = " + str(self.data[row,col])
            self.statusBar().showMessage(sms)

    def clear(self):
        """ Función que borra las gráficas y la barra de acciones

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.figure.clear()
        self.canvas.draw()
        self.figure2.clear()
        self.canvas2.draw()
        self.ventana.textEdit.clear()

    def clear1(self):
        """ Función que borra las gráficas

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        self.figure.clear()
        self.canvas.draw()
        self.figure2.clear()
        self.canvas2.draw()

    def about(self):
        """ Función que muestra cuadro de diálogo con info acerca del software

        :param self: instancia de la clase MainApp
        :type self: titi_app.MainApp
        :returns: Sin retorno
        :rtype: --
        """
        QtGui.QMessageBox.about(self, self.tr("Acerca de..."),
        self.tr("saTellITal Image viewer\n\n"
                "Autor: CENEHA - Centro de Estudios Hidroambientales \n"
                "E-mail: ceneha [at] fich.unl.edu.ar\n"
                "Version: 0.2 \n"
                "Fecha: May 2014"))
예제 #15
0
class View(QWidget):

  def __init__(self, parent = None):
    super(View, self).__init__(parent)

    self.figure = plt.figure()
    self.canvas = FigureCanvas(self.figure)
    self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)    
    toolbar = NavigationToolbar(self.canvas, self)
    
    self.navigationLayout = QHBoxLayout()
    
    layout = QHBoxLayout(self)
    self.navigations = []
    self.addNavigation(True)
    
    addIcon = QIcon.fromTheme('list-add')
    addNaviButton = QPushButton(addIcon, 'Add navigation', self)
    addNaviButton.clicked.connect(self.addNavigation)
    
    self.maxFreq = QDoubleSpinBox(self)
    self.maxFreq.setValue(10.0)
    self.maxFreq.setVisible(False)
    spectrumIcon = QIcon.fromTheme('network-wireless')
    self.spectrum = QPushButton(spectrumIcon, 'Spectrum', self)
    self.spectrum.setCheckable(True)
    self.spectrum.clicked.connect(self.plot)
    self.spectrum.toggled.connect(self.maxFreq.setVisible)
    self.maxFreq.valueChanged.connect(self.plot)
    
    saveAll = QPushButton(QIcon.fromTheme('document-save'), '', self)
    saveAll.clicked.connect(self.savePlots)
    
    self.epicenterX = QDoubleSpinBox(self)
    self.epicenterX.setValue(0.0)
    self.epicenterX.setMaximum(float('inf'))
    self.epicenterX.setVisible(False)
    self.epicenterX.valueChanged.connect(self.plot)
    self.epicenterY = QDoubleSpinBox(self)
    self.epicenterY.setValue(0.0)
    self.epicenterY.setMaximum(float('inf'))
    self.epicenterY.setVisible(False)
    self.epicenterY.valueChanged.connect(self.plot)
    self.rotate = QPushButton('Rotate', self)
    self.rotate.setCheckable(True)
    self.rotate.clicked.connect(self.plot)
    self.rotate.toggled.connect(self.epicenterX.setVisible)
    self.rotate.toggled.connect(self.epicenterY.setVisible)

    toolLayout = QHBoxLayout()
    toolLayout.addWidget(addNaviButton)
    toolLayout.addWidget(self.spectrum)
    toolLayout.addWidget(self.maxFreq)
    toolLayout.addWidget(saveAll)
    toolLayout.addWidget(self.rotate)
    toolLayout.addWidget(self.epicenterX)
    toolLayout.addWidget(self.epicenterY)
    toolLayout.addWidget(toolbar)
    plotLayout = QVBoxLayout()
    plotLayout.addLayout(toolLayout)
    plotLayout.addWidget(self.canvas)
    layout.addLayout(self.navigationLayout)
    layout.addLayout(plotLayout)
    
  def addNavigation(self, noclose = False):
    navigation = Navigation.Navigation(noclose)
    navigation.activeItemChanged.connect(self.plot)
    navigation.close.connect(self.closeNavigation)
    navigation.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum)
    self.navigationLayout.addWidget(navigation)
    self.navigations.append(navigation)
    
  def closeNavigation(self, widget):
    self.navigations.remove(widget)
    self.navigationLayout.removeWidget(widget)
    widget.deleteLater()
    self.plot()

  def plot(self):
    waveforms = []
    numPlots = 0
    names = set()
    for nav in self.navigations:
      for wf in nav.getActiveWaveforms():
        numPlots = max(numPlots, len(wf.names))
        names.update(set(wf.names))
        waveforms.append(wf)
        
    self.figure.clear()
    if numPlots > 0:
      names = list(names)
      names.sort()

      numRows = math.ceil(math.sqrt(numPlots));
      numCols = math.ceil(numPlots / numRows)
      subplots = dict()
      for i in range(0, len(names)):
        subplots[ names[i] ] = self.figure.add_subplot(numRows, numCols, i+1)

      for wf in waveforms:
        for name in wf.names:
          p = subplots[name]
          if self.spectrum.isChecked():
            n = len(wf.waveforms[name])
            dt = wf.time[1]-wf.time[0] # assume equally spaced samples
            f = scipy.fftpack.fftfreq(n, dt)
            W = dt * scipy.fftpack.fft(wf.waveforms[name])
            maxFreqIndices = numpy.argwhere(f > self.maxFreq.value())
            L = maxFreqIndices[0] if len(maxFreqIndices) > 0 else n/2
            p.loglog(f[1:L], numpy.absolute(W[1:L]))
            p.set_xlabel('f [Hz]')
          else:
            twf = wf.waveforms[name]
            if self.rotate.isChecked():
              epicenter = numpy.array([self.epicenterX.value(), self.epicenterY.value(), 0.0])
              radial = wf.coordinates - epicenter
              phi = math.acos(radial[0] / numpy.linalg.norm(radial))
              if name == 'u':
                twf = math.cos(phi) * wf.waveforms['u'] + math.sin(phi) * wf.waveforms['v']
              elif name == 'v':                
                twf = -math.sin(phi) * wf.waveforms['u'] + math.cos(phi) * wf.waveforms['v']
            p.plot(wf.time, twf)
            p.set_xlabel('t (s)')
          p.set_ylabel(name)

      self.figure.tight_layout()
    self.canvas.draw()
  
  def savePlots(self):
    filetypes = self.canvas.get_supported_filetypes_grouped()
    defaultFiletype = self.canvas.get_default_filetype()
    filters = []
    selectedFilter = ''
    for name, extensions in sorted(filetypes.iteritems()):
      filtr = '{0} ({1})'.format(name, ' '.join(['*.{0}'.format(ext) for ext in extensions]))
      if defaultFiletype in extensions:
        selectedFilter = filtr
      filters.append(filtr)
    fileName, filtr = QFileDialog.getSaveFileNameAndFilter(self, 'Choose a save location.', '', ';;'.join(filters), selectedFilter)
    fileName = os.path.splitext(str(fileName))[0]
    extension = re.search(r'\*(\.[a-zA-Z]+)', str(filtr)).group(1)
    
    maxRow = min([nav.numberOfRows() for nav in self.navigations])
    for row in range(maxRow):
      for nav in self.navigations:
        nav.selectWaveformAt(row)
      self.plot()
      self.canvas.print_figure('{0}{1:03}{2}'.format(fileName, row+1, extension))
예제 #16
0
class Browse(QtGui.QMainWindow):
    '''Class to hold the GUI browse method'''

    def __init__(self, pathDir=None, airborne=False, rhi=False):
        '''Initialize the class to create the interface'''
        super(Browse, self).__init__()
        
        # Set some parameters
        self.dirIn = pathDir
        
        # Default field and tilt angle to plot
        self.field = 'reflectivity'
        self.tilt = 0
    
        self.airborne = airborne
        self.rhi = rhi
        
        # Set size of plot
        self.XSIZE = PPI_XSIZE
        self.YSIZE = PPI_YSIZE
        self.XRNG = PPI_XRNG
        self.YRNG = PPI_YRNG
        if self.airborne:
            self.XSIZE = AIR_XSIZE
            self.YSIZE = AIR_YSIZE
            self.XRNG = AIR_XRNG
            self.YRNG = AIR_YRNG
        if self.rhi:
            self.XSIZE = RHI_XSIZE
            self.YSIZE = RHI_YSIZE
            self.XRNG = RHI_XRNG
            self.YRNG = RHI_YRNG
        
        # Set plot title and colorbar units to defaults
        self.title = None
        self.units = None
        # Initialize limits
        self._initialize_limits()
            
        # Set the default range rings
        self.RngRingList = ["None", "10 km", "20 km", "30 km", "50 km", "100 km"]
        self.RngRing = False
        
        # Find the PyArt colormap names
#        self.cm_names = pyart.graph.cm._cmapnames
        self.cm_names = [m for m in cm.datad if not m.endswith("_r")]
        self.cm_names.sort()
  
        # Create a figure for output
        self._set_fig_ax(nrows=1, ncols=1)
        
        # Initiate no tool useage
        self.ToolSelect = "No Tools"
                        
        # Launch the GUI interface
        self.LaunchGUI()      
                
        # Show an "Open" dialog box and return the path to the selected file
        self.showFileDialog()
        
        self.central_widget.setLayout(self.layout)
   
        self.show()
        
        self.pickPoint = self.fig.canvas.mpl_connect('button_press_event', self.onPick)
        
    # Allow advancement via left and right arrow keys
    # and tilt adjustment via the Up-Down arrow keys
    def keyPressEvent(self, event):
        if event.key()==QtCore.Qt.Key_Right:
            #self.slider.setValue(self.slider.value() + 1)
            self.AdvanceFileSelect(self.fileindex + 1)
        elif event.key()==QtCore.Qt.Key_Left:
            #self.slider.setValue(self.slider.value() - 1)
            self.AdvanceFileSelect(self.fileindex - 1)
        elif event.key()==QtCore.Qt.Key_Up:
            #self.slider.setValue(self.slider.value() - 1)
            self.TiltSelectCmd(self.tilt + 1)
        elif event.key()==QtCore.Qt.Key_Down:
            #self.slider.setValue(self.slider.value() - 1)
            self.TiltSelectCmd(self.tilt - 1)
        else:
            QtGui.QWidget.keyPressEvent(self, event)
            
    def onPick(self, event):
        '''Get value at the point selected by mouse click'''
        xdata = event.xdata # get event x location
        ydata = event.ydata # get event y location
        az = np.arctan2(xdata, ydata)*180./np.pi
        if az < 0:
            az = az + 360.
        rng = np.sqrt(xdata*xdata+ydata*ydata)
        azindex = np.argmin(np.abs(self.radar.azimuth['data'][self.radar.sweep_start_ray_index['data'][self.tilt]:self.radar.sweep_end_ray_index['data'][self.tilt]]-az))+self.radar.sweep_start_ray_index['data'][self.tilt]
        rngindex = np.argmin(np.abs(self.radar.range['data']-rng*1000.))
        msg = 'x = %4.2f, y = %4.2f, Azimuth = %4.2f deg., Range = %4.3f km, %s = %4.2f %s'\
        %(xdata, ydata, self.radar.azimuth['data'][azindex], self.radar.range['data'][rngindex]/1000., self.field, self.radar.fields[self.field]['data'][azindex][rngindex], self.units)
        self.statusBar().showMessage(msg)

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
     
        # Initiate a counter, used so that Tilt and Field menus are 
        # not increased every time there is a selection
        # Might be a more elegant way
        self.counter = 0

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self.statusBar()
        
        # Create the menus
        self.CreateMenu()
        
        # Create the button controls
        limsb = QtGui.QPushButton("Adjust Limits")
        limsb.setToolTip("Set data, X, and Y range limits")
        limsb.clicked.connect(self.showLimsDialog)
        titleb = QtGui.QPushButton("Title")
        titleb.setToolTip("Change plot title")
        titleb.clicked.connect(self._title_input)
        unitsb = QtGui.QPushButton("Units")
        unitsb.setToolTip("Change units string")
        unitsb.clicked.connect(self._units_input)
        
        # Create the Tools ComboBox
        self.toolsBoxUI()
        
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(8)
        
        self.layout.addWidget(limsb, 0, 0)
        self.layout.addWidget(self.toolsBox, 0, 1)
        self.layout.addWidget(titleb, 0, 2)
        self.layout.addWidget(unitsb, 0, 3)

        # Create the Tilt buttons
        self.CreateTiltWidget()
                
    def showFileDialog(self):
        '''Open a dialog box to choose file'''    
        self.qfilename = QtGui.QFileDialog.getOpenFileName(self, 'Open file', 
                self.dirIn)
        self.filename = str(self.qfilename)
        self._openfile()
        
    def showLimsDialog(self):
        self.limsDialog = QtGui.QDialog()
        u = Ui_LimsDialog(self.limsDialog, self.limits)
        u.setupUi()#self.limsDialog, self.limits

        self.limsDialog.exec_()
        
    def LaunchTiltButton(self):
        if self.windowTilt is None:
            self.windowTilt = TiltButtons(tilts=self.rTilts)
        self.windowTilt.show()
            
    def toolsBoxUI(self):
        self.toolsBox = QtGui.QComboBox()
        self.toolsBox.setToolTip("Choose a tool to apply")
        self.toolsBox.addItem("No Tools")
        self.toolsBox.addItem("Zoom/Pan")
        self.toolsBox.addItem("Reset file defaults")
        
        self.toolsBox.activated[str].connect(self.comboAction)
        
    def comboAction(self, text):
        # Check to see if Zoom/Pan was selected, if so disconnect 
        if self.ToolSelect == "Zoom/Pan":
            print "IN DISCONNECT"
            self.zp.disconnect()
        # Set the Tool to use
        self.ToolSelect = text
        
        if self.ToolSelect == "Reset file defaults":
            self._initialize_limits()
        self._update_plot()
        
    ######################
    # Help methods #
    ######################

    def _about(self):
        txOut = "This is a simple radar file browser to allow \
                 quicklooks using the DoE PyArt software"
        QtGui.QMessageBox.about(self, "About ARTView", txOut)
 
    def _get_RadarLongInfo(self):
        '''Print out the radar info to text box'''
 
        # Get the radar info form rada object and print it
        txOut = self.radar.info()
        print txOut
            
#        QtGui.QMessageBox.information(self, "Long Radar Info", str(txOut)) 
        QtGui.QMessageBox.information(self, "Long Radar Info", "See terminal window") 

    def _get_RadarShortInfo(self):
        '''Print out some basic info about the radar'''
        try:
            rname = self.radar.metadata['instrument_name']
        except:
            rname = "Info not available"
        try:
            rlon = str(self.radar.longitude['data'][0])
        except:
            rlon = "Info not available"
        try:
            rlat = str(self.radar.latitude['data'][0])
        except:
            rlat = "Info not available"
        try:
            ralt = str(self.radar.altitude['data'][0])
            raltu = self.radar.altitude['units'][0]
        except:
            ralt = "Info not available"
            raltu = " "
        try:
            maxr = str(self.radar.instrument_parameters['unambiguous_range']['data'][0])
            maxru = self.radar.instrument_parameters['unambiguous_range']['units'][0]
        except:
            maxr = "Info not available"
            maxru = " "
        try:
            nyq = str(self.radar.instrument_parameters['nyquist_velocity']['data'][0])
            nyqu = self.radar.instrument_parameters['nyquist_velocity']['units'][0]
        except:
            nyq =  "Info not available"
            nyqu = " "
        try:
            bwh = str(self.radar.instrument_parameters['radar_beam_width_h']['data'][0])
            bwhu = self.radar.instrument_parameters['radar_beam_width_h']['units'][0]
        except:
            bwh = "Info not available"
            bwhu = " "
        try:
            bwv = str(self.radar.instrument_parameters['radar_beam_width_v']['data'][0])
            bwvu = self.radar.instrument_parameters['radar_beam_width_v']['units'][0]
        except:
            bwv = "Info not available"
            bwvu = " "
        try:
            pw = str(self.radar.instrument_parameters['pulse_width']['data'][0])
            pwu = self.radar.instrument_parameters['pulse_width']['units'][0]
        except:
            pw = "Info not available"
            pwu = " "
        try:
            ngates = str(self.radar.ngates)
        except:
            ngates = "Info not available"
        try:
            nsweeps = str(self.radar.nsweeps)
        except:
            nsweeps = "Info not available"
        
        txOut = (('Radar Name: %s\n'% rname) +\
        ('Radar longitude: %s\n'% rlon) + \
        ('Radar latitude: %s\n'% rlat) + \
        ('Radar altitude: %s %s\n'% (ralt, raltu)) + \
        ('    \n') + \
        ('Unambiguous range: %s %s\n'% (maxr, maxru)) + \
        ('Nyquist velocity: %s %s\n'% (nyq, nyqu)) + \
        ('    \n') + \
        ('Radar Beamwidth, horiz: %s %s\n'% (bwh, bwhu)) + \
        ('Radar Beamwidth, vert: %s %s\n'% (bwv, bwvu)) + \
        ('Pulsewidth: %s %s \n'% (pw, pwu)) + \
        ('    \n') + \
        ('Number of gates: %s\n'% ngates) + \
        ('Number of sweeps: %s\n'% nsweeps))
        
        QtGui.QMessageBox.information(self, "Short Radar Info", txOut) 
        
    ######################
    # Menu build methods #
    ######################
 
    def CreateMenu(self):
        '''Create a selection menu'''
        self.menubar = self.menuBar()
        
        self.AddFileMenu()
        self.AddAboutMenu()
        self.AddPlotMenu()
        self.AddFileAdvanceMenu()
        

    def AddFileMenu(self):
        self.filemenu = self.menubar.addMenu('&File')
               
        openFile = QtGui.QAction('Open', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('Open new File')
        openFile.triggered.connect(self.showFileDialog)
        
        quicksaveImage = QtGui.QAction('Quick Save Image', self)  
        quicksaveImage.setShortcut('Ctrl+D')
        quicksaveImage.setStatusTip('Save Image to local directory with default name')
        quicksaveImage.triggered.connect(self._quick_savefile)
                
        saveImage = QtGui.QAction('Save Image', self)  
        saveImage.setShortcut('Ctrl+S')
        saveImage.setStatusTip('Save Image using dialog')
        saveImage.triggered.connect(self._savefile)
                
        exitApp = QtGui.QAction('Close', self)  
        exitApp.setShortcut('Ctrl+Q')
        exitApp.setStatusTip('Exit ARTView')
        exitApp.triggered.connect(self.close)
        
        self.filemenu.addAction(openFile)
        self.filemenu.addAction(quicksaveImage)
        self.filemenu.addAction(saveImage)
        self.filemenu.addAction(exitApp)
        
    def AddAboutMenu(self):
        '''Add Help item to menu bar'''
        self.aboutmenu = self.menubar.addMenu('About')

        self._aboutArtview = QtGui.QAction('ARTView', self)
        self._aboutArtview.setStatusTip('About ARTView')
        self._aboutArtview.triggered.connect(self._about)
        
        self.RadarShort = QtGui.QAction('Radar Short', self)
        self.RadarShort.setStatusTip('Print Short Radar Structure Info')
        self.RadarShort.triggered.connect(self._get_RadarShortInfo)
        
        self.RadarLong = QtGui.QAction('Radar Long', self)
        self.RadarLong.setStatusTip('Print Long Radar Structure Info')
        self.RadarLong.triggered.connect(self._get_RadarLongInfo)
        
        self.aboutmenu.addAction(self._aboutArtview)
        self.aboutmenu.addAction(self.RadarShort)
        self.aboutmenu.addAction(self.RadarLong)
        
 
    def AddPlotMenu(self):
        '''Add Plot item to menu bar'''
        self.plotmenu = self.menubar.addMenu('&Plot')
        
        # Add submenus
        self.fieldmenu = self.plotmenu.addMenu('Field')
        if self.airborne or self.rhi:
            pass
        else:
            self.tiltmenu = self.plotmenu.addMenu('Tilt')
            self.rngringmenu = self.plotmenu.addMenu('Set Range Rings')
        self.cmapmenu = self.plotmenu.addMenu('Colormap')


    def AddFileAdvanceMenu(self):
        '''Add an option to advance to next or previous file'''
        self.advancemenu = self.menubar.addMenu("Advance file")

    def AddTiltMenu(self):
        '''Add a menu to change tilt angles of current plot'''
        for ntilt in self.rTilts:
            TiltAction = self.tiltmenu.addAction("Tilt %d"%(ntilt+1))
            TiltAction.triggered[()].connect(lambda ntilt=ntilt: self.TiltSelectCmd(ntilt))

    def AddFieldMenu(self):
        '''Add a menu to change current plot field'''
        for nombre in self.fieldnames:
            FieldAction = self.fieldmenu.addAction(nombre)
            FieldAction.triggered[()].connect(lambda nombre=nombre: self.FieldSelectCmd(nombre))
            
    def AddRngRingMenu(self):
        '''Add a menu to set range rings'''
        for RngRing in self.RngRingList:
            RingAction = self.rngringmenu.addAction(RngRing)
            RingAction.triggered[()].connect(lambda RngRing=RngRing: self.RngRingSelectCmd(RngRing))
    
    def AddNextPrevMenu(self):
        '''Add an option to advance to next or previous file'''
        nextAction = self.advancemenu.addAction("Next")
        nextAction.triggered[()].connect(lambda findex=self.fileindex + 1: self.AdvanceFileSelect(findex))
        
        prevAction = self.advancemenu.addAction("Previous")
        prevAction.triggered[()].connect(lambda findex=self.fileindex - 1: self.AdvanceFileSelect(findex))
        
        firstAction = self.advancemenu.addAction("First")
        firstAction.triggered[()].connect(lambda findex=0: self.AdvanceFileSelect(findex))
        
        lastAction = self.advancemenu.addAction("Last")
        lastAction.triggered[()].connect(lambda findex=(len(self.filelist) - 1): self.AdvanceFileSelect(findex))
         
    def AddCmapMenu(self):
        '''Add a menu to change colormap used for plot'''
        for cm_name in self.cm_names:
            cmapAction = self.cmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap"%cm_name)
            cmapAction.triggered[()].connect(lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
    
    ########################
    # Button methods #
    ########################

    def CreateTiltWidget(self):
        '''Create a widget to store radio buttons to control tilt adjust'''
        self.radioBox = QtGui.QGroupBox("Tilt Selection")
        self.rBox_layout = QtGui.QVBoxLayout(self.radioBox)
        
    def SetTiltRadioButtons(self):
        '''Set a tilt selection using radio buttons'''
        # Need to first create each tilt button and connect a value when selected
        for ntilt in self.rTilts:
            tiltbutton = QtGui.QRadioButton("Tilt %d"%(ntilt+1), self.radioBox)
            QtCore.QObject.connect(tiltbutton, QtCore.SIGNAL("clicked()"), \
                         partial(self.TiltSelectCmd, ntilt))

            self.rBox_layout.addWidget(tiltbutton)
		
        self.radioBox.setLayout(self.rBox_layout)
		
        return self.radioBox

    #############################
    # Limit entry methods #
    #############################
            
    def _lims_input(self, entry):
        '''Retrieve new limits input'''
        if entry['dmin'] is not None:
            self.limits['vmin'] = entry['dmin']
        if entry['dmax'] is not None:
            self.limits['vmax'] = entry['dmax']
        if entry['xmin'] is not None:
            self.limits['xmin'] = entry['xmin']
        if entry['xmax'] is not None:
            self.limits['xmax'] = entry['xmax']
        if entry['ymin'] is not None:
            self.limits['ymin'] = entry['ymin']
        if entry['ymax'] is not None:
            self.limits['ymax'] = entry['ymax']
        self._update_plot()

    def _title_input(self):
        '''Retrieve new plot title'''
        if self.title is None:
            old_val = ''
        else:
            old_val = self.title
        val, entry = QtGui.QInputDialog.getText(self, "Plot Title", \
                  "Title:", 0, old_val)
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units'''
        if self.units is None:
            old_val = ''
        else:
            old_val = self.units
        val, entry = QtGui.QInputDialog.getText(self, "Plot Units", \
                  "Units:", 0, old_val)
        if entry is True:
            self.units = val
            self._update_plot()
        
    ########################
    # Selectionion methods #
    ########################
    
    def TiltSelectCmd(self, ntilt):
        '''Captures a selection and redraws the field with new tilt'''
        print ntilt
        self.tilt = ntilt
        self._update_plot()

    def FieldSelectCmd(self, nombre):
        '''Captures a selection and redraws the new field'''
        self.field = nombre
        self._initialize_limits()
        self.units = None
        self._update_plot()
        
    def RngRingSelectCmd(self, ringSel):
        '''Captures selection and redraws the field with range rings'''
        if ringSel is "None":
            self.RngRing = False
        else:
            self.RngRing = True
            # Find the unambigous range of the radar
            try:
                unrng = int(self.radar.instrument_parameters['unambiguous_range']['data'][0]/1000)
            except:
                unrng = int(self.limits['xmax'])
            
            # Set the step
            if ringSel == '10 km':
                ringdel = 10
            if ringSel == '20 km':
                ringdel = 20
            if ringSel == '30 km':
                ringdel = 30
            if ringSel == '50 km':
                ringdel = 50
            if ringSel == '100 km':
                ringdel = 100
                
            # Calculate an array of range rings
            self.RNG_RINGS = range(ringdel, unrng, ringdel)
        
        self._update_plot()
        
    def cmapSelectCmd(self, cm_name):
        '''Captures selection of new cmap and redraws'''
        self.CMAP = cm_name
        self._update_plot()
        
    def AdvanceFileSelect(self, findex):
        '''Captures a selection and redraws figure with new file'''
        if findex > len(self.filelist):
            print len(self.filelist)
            msg = "End of directory, cannot advance"
            self._ShowWarning(msg)
            findex = (len(self.filelist) - 1)
            return
        if findex < 0:
            msg = "Beginning of directory, must move forward"
            self._ShowWarning(msg)
            findex = 0
            return
        self.fileindex = findex
        self.filename = self.dirIn + "/" + self.filelist[findex]
        self._openfile()

    ########################
    # Menu display methods #
    ########################
 
    def _openfile(self):
        '''Open a file via a file selection window'''
        print "Opening file " + self.filename
        
        # Update to  current directory when file is chosen
        self.dirIn = os.path.dirname(self.filename)
        
        # Get a list of files in the working directory
        self.filelist = os.listdir(self.dirIn)
        
        self.fileindex = self.filelist.index(os.path.basename(self.filename))
     
        # Read the data from file
        try:
            self.radar = pyart.io.read(self.filename)
        except:
            msg = "This is not a recognized radar file"
            self._ShowWarning(msg)
            return
         
        # In case the flags were not used at startup
        # Check to see if this is an aircraft or rhi file
        if self.counter == 0:
            self._check_file_type()
            self._set_figure_canvas()

        # Increment counter to know whether to renew Tilt and field menus
        # If > 1 then remove the pre-existing menus before redrawing
        self.counter += 1
        
        if self.counter > 1:
            self.fieldmenu.clear()
            self.advancemenu.clear()
           
            if self.airborne or self.rhi:
                pass
            else:
                self.tiltmenu.clear()
                self.rngringmenu.clear()
                self.radioBox.deleteLater()

        # Get the tilt angles
        self.rTilts = self.radar.sweep_number['data'][:]
        # Get field names
        self.fieldnames = self.radar.fields.keys()

        # Set up the menus associated with scanning ground radars
        if self.airborne or self.rhi:
            pass
        else:
            self.CreateTiltWidget()
            self.layout.addWidget(self.SetTiltRadioButtons(), 1, 6, 6, 1)
            self.AddRngRingMenu()
            self.AddTiltMenu()
        self.AddFieldMenu()
        self.AddNextPrevMenu()
        self.AddCmapMenu()
        self.units = None
        self.title = None
        self._update_plot()
        
    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self, nrows=1, ncols=1):
        '''Set the figure and axis to plot to'''
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        xwidth = 0.7
        yheight = 0.7 * float(self.YSIZE)/float(self.XSIZE)
        self.ax = self.fig.add_axes([0.2, 0.2, xwidth, yheight])
        self.cax = self.fig.add_axes([0.2,0.10, xwidth, 0.02])
        
        # We want the axes cleared every time plot() is called
        #self.axes.hold(False)
        
    def _set_fig_ax_rhi(self):
        '''Change figure size and limits if RHI'''
        if self.rhi:
            self.XSIZE = RHI_XSIZE
            self.YSIZE = RHI_YSIZE
            self.limits['ymin'] = RHI_YRNG[0]
            self.limits['ymax'] = RHI_YRNG[1]
        if self.airborne:
            self.XSIZE = AIR_XSIZE
            self.YSIZE = AIR_YSIZE
            self.limits['xmin'] = AIR_XRNG[0]
            self.limits['xmax'] = AIR_XRNG[1]
            self.limits['ymin'] = AIR_YRNG[0]
            self.limits['ymax'] = AIR_YRNG[1]
        self.fig.set_size_inches(self.XSIZE, self.YSIZE)
        self._set_fig_ax()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 7, 6)

    def _update_plot(self):
        '''Renew the plot'''
        # This is a bit of a hack to ensure that the viewer works with files
        # withouth "standard" output as defined by PyArt
        # Check to see if the field 'reflectivity' exists for the initial open
        self._check_default_field()
    
        # Create the plot with PyArt RadarDisplay 
        # Always intitiates at lowest elevation angle
        self.ax.cla()

        # Reset to default title if user entered nothing w/ Title button
        if self.title == '':
            self.title = None
        
        # If Zoom/Pan selected, Set up the zoom/pan functionality
        if self.ToolSelect == "Zoom/Pan":
            scale = 1.1
            self.zp = ZoomPan(self.ax, self.limits, base_scale = scale)
            #figZoom = self.zp.zoom()
            #figPan = self.zp.pan_factory(self.limits)
            self.zp.connect()
        
        if self.airborne:
            self.display = pyart.graph.RadarDisplay_Airborne(self.radar)
            
            self.plot = self.display.plot_sweep_grid(self.field, \
                                vmin=self.limits['vmin'], vmax=self.limits['vmax'],\
                                colorbar_flag=False, cmap=self.CMAP,\
                                ax=self.ax, title=self.title)
            self.display.set_limits(xlim=(self.limits['xmin'], self.limits['xmax']),\
                                    ylim=(self.limits['ymin'], self.limits['ymax']),\
                                    ax=self.ax)
            self.display.plot_grid_lines()
        else:
            self.display = pyart.graph.RadarDisplay(self.radar)
            if self.radar.scan_type != 'rhi':
                # Create Plot
                if self.tilt < len(self.rTilts):
                    pass
                else:
                    self.tilt = 0
                self.plot = self.display.plot_ppi(self.field, self.tilt,\
                                vmin=self.limits['vmin'], vmax=self.limits['vmax'],\
                                colorbar_flag=False, cmap=self.CMAP,\
                                ax=self.ax, title=self.title)
                # Set limits
                self.display.set_limits(xlim=(self.limits['xmin'], self.limits['xmax']),\
                                        ylim=(self.limits['ymin'], self.limits['ymax']),\
                                        ax=self.ax)
                # Add range rings
                if self.RngRing:
                    self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)
                # Add radar location
                self.display.plot_cross_hair(5., ax=self.ax)
            else:
                self.plot = self.display.plot_rhi(self.field, self.tilt,\
                                vmin=self.limits['vmin'], vmax=self.limits['vmax'],\
                                colorbar_flag=False, cmap=self.CMAP,\
                                ax=self.ax, title=self.title)
                self.display.set_limits(xlim=(self.limits['xmin'], self.limits['xmax']),\
                                        ylim=(self.limits['ymin'], self.limits['ymax']),\
                                        ax=self.ax)
                # Add range rings
                if self.RngRing:
                    self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)
        
        norm = mlabNormalize(vmin=self.limits['vmin'],\
                                           vmax=self.limits['vmax'])
        self.cbar=mlabColorbarBase(self.cax, cmap=self.CMAP,\
                                                norm=norm, orientation='horizontal')
        # colorbar - use specified units or default depending on
        # what has or has not been entered
        if self.units is None or self.units == '':
            try:
                self.units = self.radar.fields[self.field]['units']
            except:
                self.units = ''
        self.cbar.set_label(self.units)
        
        print "Plotting %s field, Tilt %d" % (self.field, self.tilt+1)
        self.canvas.draw()
 
    #########################
    # Get and check methods #
    #########################
    def _initialize_limits(self):
        if self.field == 'reflectivity':
            self.vminmax = (Z_LIMS[0], Z_LIMS[1])
            self.CMAP = 'gist_ncar'
        elif self.field == 'DBZ':
            self.vminmax = (Z_LIMS[0], Z_LIMS[1])
            self.CMAP = 'gist_ncar'
        elif self.field == 'velocity':
            self.vminmax = (VR_LIMS[0], VR_LIMS[1])
            self.CMAP = 'RdBu_r'
        elif self.field == 'VEL':
            self.vminmax = (VR_LIMS[0], VR_LIMS[1])
            self.CMAP = 'RdBu_r'
        elif self.field == 'differential_reflectivity':
            self.vminmax = (ZDR_LIMS[0], ZDR_LIMS[1])
            self.CMAP = 'RdYlBu_r'
        elif self.field == 'cross_correlation_ratio':
            self.vminmax = (RHO_HV_LIMS[0], RHO_HV_LIMS[1])
            self.CMAP = 'cool'
        elif self.field == 'differential_phase':
            self.vminmax = (KDP_LIMS[0], KDP_LIMS[1])
            self.CMAP = 'YlOrBr'
        elif self.field == 'normalized_coherent_power':
            self.vminmax = (NCP_LIMS[0], NCP_LIMS[1])
            self.CMAP = 'jet'
        elif self.field == 'spectrum_width':
            self.vminmax = (SW_LIMS[0], SW_LIMS[1])
            self.CMAP = 'gist_ncar'
        elif self.field == 'specific_differential_phase':
            self.vminmax = (PHIDP_LIMS[0], PHIDP_LIMS[1]) 
            self.CMAP = 'RdBu_r'
        elif self.field == 'total_power':
            self.vminmax = (TP_LIMS[0], TP_LIMS[1])
            self.CMAP = 'jet'
           
        limit_strs = ('vmin', 'vmax', 'xmin', 'xmax', 'ymin', 'ymax')
        self.limits = {}
        
        # Now pull the default values
        self.limits['vmin'] = self.vminmax[0]
        self.limits['vmax'] = self.vminmax[1]
        self.limits['xmin'] = self.XRNG[0]
        self.limits['xmax'] = self.XRNG[1]
        self.limits['ymin'] = self.YRNG[0]
        self.limits['ymax'] = self.YRNG[1]
        
# #    def _build_cmap_dict(self):
# #        self.cmap_dict = {}
# #        self.cmap_dict['gist_ncar'] = matcm.get_cmap(name='gist_ncar')
# #        self.cmap_dict['RdBu_r'] = matcm.get_cmap(name='RdBu_r')
# #        self.cmap_dict['RdYlBu_r'] = matcm.get_cmap(name='RdYlBu_r
# #        self.cmap_dict['cool'] = matcm.get_cmap(name='cool
# #        self.cmap_dict['YlOrBr'] = matcm.get_cmap(name='YlOrBr
# #        self.cmap_dict['jet'] = matcm.get_cmap(name='jet
# #        self.cmap_dict['
# #        self.cmap_dict['
        
    def _check_default_field(self):
        '''Hack to perform a check on reflectivity to make it work with 
        a larger number of files
        This should only occur upon start up with a new file'''
        if self.field == 'reflectivity':
            if self.field in self.fieldnames:
                pass
            elif 'CZ' in self.fieldnames:
                self.field = 'CZ'
            elif 'DZ' in self.fieldnames:
                self.field = 'DZ'
            elif 'dbz' in self.fieldnames:
                self.field = 'dbz'
            elif 'DBZ' in self.fieldnames:
                self.field = 'DBZ'
            elif 'dBZ' in self.fieldnames:
                self.field = 'dBZ'
            elif 'Z' in self.fieldnames:
                self.field = 'Z'
            elif 'DBZ_S'in self.fieldnames:
                self.field = 'DBZ_S'
            elif 'reflectivity_horizontal'in self.fieldnames:
                self.field = 'reflectivity_horizontal'

                
    def _check_file_type(self):
        '''Check file to see if the file is airborne or rhi'''
        if self.radar.scan_type != 'rhi':
            pass
        else:
            try:
                (self.radar.metadata['platform_type'] == 'aircraft_tail') or \
                (self.radar.metadata['platform_type'] == 'aircraft')
                self.airborne = True
            except:
                self.rhi = True
            
            self._set_fig_ax_rhi()
 
    ########################
    # Warning methods #
    ########################
    def _ShowWarning(self, msg):
        '''Show a warning message'''
        flags = QtGui.QMessageBox.StandardButton()
        response = QtGui.QMessageBox.warning(self, "Warning!",
                                             msg, flags)
        if response == 0:
            print msg
        else:
            print "Warning Discarded!"
 
    ########################
    # Image save methods #
    ########################
    def _quick_savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display'''
        PNAME = self.display.generate_filename(self.field, self.tilt, ext=IMAGE_EXT)
        print "Creating "+ PNAME
        
    def _savefile(self, PTYPE=IMAGE_EXT):
        PBNAME = self.display.generate_filename(self.field, self.tilt, ext=IMAGE_EXT)
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(self, 'Save file', '', file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusBar().showMessage('Saved to %s' % path)
예제 #17
0
class RadarDisplay(Component):
    '''
    Class to create a display plot, using a returned Radar structure
    from the PyArt pyart.graph package.
    '''

    Vradar = None  #: see :ref:`shared_variable`
    Vfield = None  #: see :ref:`shared_variable`
    Vtilt = None  #: see :ref:`shared_variable`
    Vlims = None  #: see :ref:`shared_variable`
    Vcmap = None  #: see :ref:`shared_variable`
    Vgatefilter = None  #: see :ref:`shared_variable`

    @classmethod
    def guiStart(self, parent=None):
        '''Graphical interface for starting this class'''
        args = _DisplayStart().startDisplay()
        return self(**args), True

    def __init__(self, Vradar, Vfield, Vtilt, Vlims=None, Vcmap=None,
                 Vgatefilter=None, name="RadarDisplay", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        Vradar : :py:class:`~artview.core.core.Variable` instance
            Radar signal variable.
        Vfield : :py:class:`~artview.core.core.Variable` instance
            Field signal variable.
        Vtilt : :py:class:`~artview.core.core.Variable` instance
            Tilt signal variable.
        [Optional]
        Vlims : :py:class:`~artview.core.core.Variable` instance
            Limits signal variable.
            A value of None will instantiate a limits variable.
        Vcmap : :py:class:`~artview.core.core.Variable` instance
            Colormap signal variable.
            A value of None will instantiate a colormap variable.
        Vgatefilter : :py:class:`~artview.core.core.Variable` instance
            Gatefilter signal variable.
            A value of None will instantiate a empty variable.
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        Notes
        -----
        This class records the selected button and passes the
        change value back to variable.
        '''
        super(RadarDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)
        # Set up signal, so that DISPLAY can react to
        # external (or internal) changes in radar, field,
        # lims and tilt (expected to be Core.Variable instances)
        # The capital V so people remember using ".value"
        self.Vradar = Vradar
        self.Vfield = Vfield
        self.Vtilt = Vtilt
        if Vlims is None:
            self.Vlims = Variable(None)
        else:
            self.Vlims = Vlims

        if Vcmap is None:
            self.Vcmap = Variable(None)
        else:
            self.Vcmap = Vcmap

        if Vgatefilter is None:
            self.Vgatefilter = Variable(None)
        else:
            self.Vgatefilter = Vgatefilter

        self.sharedVariables = {"Vradar": self.NewRadar,
                                "Vfield": self.NewField,
                                "Vtilt": self.NewTilt,
                                "Vlims": self.NewLims,
                                "Vcmap": self.NewCmap,
                                "Vgatefilter": self.NewGatefilter}

        # Connect the components
        self.connectAllVariables()

        self.plot_type = None

        # Set plot title and colorbar units to defaults
        self.title = self._get_default_title()
        self.units = self._get_default_units()

        # Set the default range rings
        self.RngRingList = ["None", "10 km", "20 km", "30 km",
                            "50 km", "100 km"]
        self.RngRing = False

        # Find the PyArt colormap names
#        self.cm_names = [m for m in cm.datad if not m.endswith("_r")]
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create tool dictionary
        self.tools = {}

        # Set up Default limits and cmap
        if Vlims is None:
            self._set_default_limits(strong=False)
        if Vcmap is None:
            self._set_default_cmap(strong=False)

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Initialize radar variable
        self.NewRadar(None, None, True)

        self.show()

    def keyPressEvent(self, event):
        '''Allow tilt adjustment via the Up-Down arrow keys.'''
        if event.key() == QtCore.Qt.Key_Up:
            self.TiltSelectCmd(self.Vtilt.value + 1)
        elif event.key() == QtCore.Qt.Key_Down:
            self.TiltSelectCmd(self.Vtilt.value - 1)
        else:
            super(RadarDisplay, self).keyPressEvent(event)

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(8)

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add buttons along display for user control
        self.addButtons()
        self.setUILayout()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    ##################################
    # User display interface methods #
    ##################################

    def addButtons(self):
        '''Add a series of buttons for user control over display.'''
        # Create the Display controls
        self._add_displayBoxUI()
        # Create the Tilt controls
        self._add_tiltBoxUI()
        # Create the Field controls
        self._add_fieldBoxUI()
        # Create the Tools controls
        self._add_toolsBoxUI()
        # Create the Informational label at top
        self._add_infolabel()

    def setUILayout(self):
        '''Setup the button/display UI layout.'''
        self.layout.addWidget(self.tiltBox, 0, 0)
        self.layout.addWidget(self.fieldBox, 0, 1)
        self.layout.addWidget(self.dispButton, 0, 2)
        self.layout.addWidget(self.toolsButton, 0, 3)
        self.layout.addWidget(self.infolabel, 0, 4)

    #############################
    # Functionality methods #
    #############################

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(
            self.Vlims.value, self.Vcmap.value, self.name)
        if change == 1:
            self.Vcmap.change(cmap)
            self.Vlims.change(limits)

    def _fillTiltBox(self):
        '''Fill in the Tilt Window Box with current elevation angles.'''
        self.tiltBox.clear()
        self.tiltBox.addItem("Tilt Window")
        # Loop through and create each tilt button
        elevs = self.Vradar.value.fixed_angle['data'][:]
        for i, ntilt in enumerate(self.rTilts):
            btntxt = "%2.1f deg (Tilt %d)" % (elevs[i], i+1)
            self.tiltBox.addItem(btntxt)

    def _fillFieldBox(self):
        '''Fill in the Field Window Box with current variable names.'''
        self.fieldBox.clear()
        self.fieldBox.addItem("Field Window")
        # Loop through and create each field button
        for field in self.fieldnames:
            self.fieldBox.addItem(field)

    def _tiltAction(self, text):
        '''Define action for Tilt Button selection.'''
        if text == "Tilt Window":
            self._open_tiltbuttonwindow()
        else:
            ntilt = int(text.split("(Tilt ")[1][:-1])-1
            self.TiltSelectCmd(ntilt)

    def _fieldAction(self, text):
        '''Define action for Field Button selection.'''
        if text == "Field Window":
            self._open_fieldbuttonwindow()
        else:
            self.FieldSelectCmd(str(text))

    def _GateFilterToggleAction(self):
        '''Define action for GateFilterToggle menu selection.'''
        if self.gatefilterToggle.isChecked():
            self.gatefilterToggle.setText("GateFilter On")
        else:
            self.gatefilterToggle.setText("GateFilter Off")
        self._update_plot()
        

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog_with_reset(
            self.title, "Plot Title", "Title:", self._get_default_title())
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog_with_reset(
            self.units, "Plot Units", "Units:", self._get_default_units())
        if entry is True:
            self.units = val
            self._update_plot()

    def _open_tiltbuttonwindow(self):
        '''Open a TiltButtonWindow instance.'''
        from .level import LevelButtonWindow
        self.tiltbuttonwindow = LevelButtonWindow(
            self.Vtilt, plot_type=self.plot_type, Vcontainer=self.Vradar,
            name=self.name+" Tilt Selection", parent=self.parent)

    def _open_fieldbuttonwindow(self):
        '''Open a FieldButtonWindow instance.'''
        from .field import FieldButtonWindow
        self.fieldbuttonwindow = FieldButtonWindow(
            self.Vradar, self.Vfield,
            name=self.name+" Field Selection", parent=self.parent)

    def _add_RngRing_to_button(self):
        '''Add a menu to display range rings on plot.'''
        for RngRing in self.RngRingList:
            RingAction = self.dispRngRingmenu.addAction(RngRing)
            RingAction.setStatusTip("Apply Range Rings every %s" % RngRing)
            RingAction.triggered[()].connect(
                lambda RngRing=RngRing: self.RngRingSelectCmd(RngRing))
            self.dispRngRing.setMenu(self.dispRngRingmenu)

    def _add_cmaps_to_button(self):
        '''Add a menu to change colormap used for plot.'''
        for cm_name in self.cm_names:
            cmapAction = self.dispCmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap" % cm_name)
            cmapAction.triggered[()].connect(
                lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
            self.dispCmap.setMenu(self.dispCmapmenu)

    def _add_displayBoxUI(self):
        '''Create the Display Options Button menu.'''
        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = dispmenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
        self.gatefilterToggle = QtGui.QAction(
            'GateFilter On', dispmenu, checkable=True,
            triggered=self._GateFilterToggleAction)#_update_plot)
        dispmenu.addAction(self.gatefilterToggle)
        self.gatefilterToggle.setChecked(True)
        dispTitle = dispmenu.addAction("Change Title")
        dispTitle.setToolTip("Change plot title")
        dispUnit = dispmenu.addAction("Change Units")
        dispUnit.setToolTip("Change units string")
        self.dispRngRing = dispmenu.addAction("Add Range Rings")
        self.dispRngRingmenu = QtGui.QMenu("Add Range Rings")
        self.dispRngRingmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        self.dispCmap = dispmenu.addAction("Change Colormap")
        self.dispCmapmenu = QtGui.QMenu("Change Cmap")
        self.dispCmapmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        dispQuickSave = dispmenu.addAction("Quick Save Image")
        dispQuickSave.setShortcut("Ctrl+D")
        dispQuickSave.setToolTip(
            "Save Image to local directory with default name")
        dispSaveFile = dispmenu.addAction("Save Image")
        dispSaveFile.setShortcut("Ctrl+S")
        dispSaveFile.setStatusTip("Save Image using dialog")

        dispLimits.triggered[()].connect(self._open_LimsDialog)
        dispTitle.triggered[()].connect(self._title_input)
        dispUnit.triggered[()].connect(self._units_input)
        dispQuickSave.triggered[()].connect(self._quick_savefile)
        dispSaveFile.triggered[()].connect(self._savefile)

        self._add_RngRing_to_button()
        self._add_cmaps_to_button()
        self.dispButton.setMenu(dispmenu)

    def _add_tiltBoxUI(self):
        '''Create the Tilt Selection ComboBox.'''
        self.tiltBox = QtGui.QComboBox()
        self.tiltBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.tiltBox.setToolTip("Select tilt elevation angle to display.\n"
                                "'Tilt Window' will launch popup.\n"
                                "Up/Down arrow keys Increase/Decrease tilt.")
        self.tiltBox.activated[str].connect(self._tiltAction)

    def _add_fieldBoxUI(self):
        '''Create the Field Selection ComboBox.'''
        self.fieldBox = QtGui.QComboBox()
        self.fieldBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.fieldBox.setToolTip("Select variable/field in data file.\n"
                                 "'Field Window' will launch popup.\n")
        self.fieldBox.activated[str].connect(self._fieldAction)

    def _add_toolsBoxUI(self):
        '''Create the Tools Button menu.'''
        self.toolsButton = QtGui.QPushButton("Toolbox")
        self.toolsButton.setFocusPolicy(QtCore.Qt.NoFocus)
        self.toolsButton.setToolTip("Choose a tool to apply")
        toolmenu = QtGui.QMenu(self)
        toolZoomPan = toolmenu.addAction("Zoom/Pan")
        toolValueClick = toolmenu.addAction("Click for Value")
        toolSelectRegion = toolmenu.addAction("Select a Region of Interest")
        toolReset = toolmenu.addAction("Reset Tools")
        toolDefault = toolmenu.addAction("Reset File Defaults")
        toolZoomPan.triggered[()].connect(self.toolZoomPanCmd)
        toolValueClick.triggered[()].connect(self.toolValueClickCmd)
        toolSelectRegion.triggered[()].connect(self.toolSelectRegionCmd)
        toolReset.triggered[()].connect(self.toolResetCmd)
        toolDefault.triggered[()].connect(self.toolDefaultCmd)
        self.toolsButton.setMenu(toolmenu)

    def _add_infolabel(self):
        '''Create an information label about the display'''
        self.infolabel = QtGui.QLabel("Radar: \n"
                                      "Field: \n"
                                      "Tilt: ", self)
        self.infolabel.setStyleSheet('color: red; font: italic 10px')
        self.infolabel.setToolTip("Filename not loaded")

    def _update_infolabel(self):
        if self.Vradar.value is None:
            return
        self.infolabel.setText("Radar: %s\n"
                               "Field: %s\n"
                               "Tilt: %d" % (
                                   self.Vradar.value.metadata[
                                       'instrument_name'],
                                   self.Vfield.value,
                                   self.Vtilt.value+1))
        if hasattr(self.Vradar.value, 'filename'):
            self.infolabel.setToolTip(self.Vradar.value.filename)

    ########################
    # Selectionion methods #
    ########################

    def NewRadar(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vradar <artview.core.core.Variable>`.

        This will:

        * Update fields and tilts lists and MenuBoxes
        * Check radar scan type and reset limits if needed
        * Reset units and title
        * If strong update: update plot
        '''
        # test for None
        if self.Vradar.value is None:
            self.fieldBox.clear()
            self.tiltBox.clear()
            return

        # Get the tilt angles
        self.rTilts = self.Vradar.value.sweep_number['data'][:]
        # Get field names
        self.fieldnames = self.Vradar.value.fields.keys()

        # Check the file type and initialize limts
        self._check_file_type()

        # Update field and tilt MenuBox
        self._fillTiltBox()
        self._fillFieldBox()

        self.units = self._get_default_units()
        self.title = self._get_default_title()
        if strong:
            self._update_plot()
            self._update_infolabel()

    def NewField(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vfield <artview.core.core.Variable>`.

        This will:

        * Reset colormap
        * Reset units
        * Update fields MenuBox
        * If strong update: update plot
        '''
        self._set_default_cmap(strong=False)
        self.units = self._get_default_units()
        self.title = self._get_default_title()
        idx = self.fieldBox.findText(value)
        self.fieldBox.setCurrentIndex(idx)
        if strong:
            self._update_plot()
            self._update_infolabel()

    def NewLims(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlims <artview.core.core.Variable>`.

        This will:

        * If strong update: update axes
        '''
        if strong:
            self._update_axes()

    def NewCmap(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vcmap <artview.core.core.Variable>`.

        This will:

        * If strong update: update plot
        '''
        if strong:
            self._update_plot()

    def NewGatefilter(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vgatefilter <artview.core.core.Variable>`.

        This will:

        * If strong update: update plot
        '''
        if strong:
            self._update_plot()

    def NewTilt(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vtilt <artview.core.core.Variable>`.

        This will:

        * Update tilt MenuBox
        * If strong update: update plot
        '''
        # +1 since the first one is "Tilt Window"
        self.tiltBox.setCurrentIndex(value+1)
        if strong:
            self._update_plot()
            self._update_infolabel()

    def TiltSelectCmd(self, ntilt):
        '''
        Captures tilt selection and update tilt
        :py:class:`~artview.core.core.Variable`.
        '''
        if ntilt < 0:
            ntilt = len(self.rTilts)-1
        elif ntilt >= len(self.rTilts):
            ntilt = 0
        self.Vtilt.change(ntilt)

    def FieldSelectCmd(self, name):
        '''
        Captures field selection and update field
        :py:class:`~artview.core.core.Variable`.
        '''
        self.Vfield.change(name)

    def RngRingSelectCmd(self, ringSel):
        '''
        Captures Range Ring selection and
        redraws the field with range rings.
        '''
        if ringSel is "None":
            self.RngRing = False
        else:
            self.RngRing = True
            # Find the unambigous range of the radar
            try:
                unrng = int(self.Vradar.value.instrument_parameters[
                    'unambiguous_range']['data'][0]/1000)
            except:
                unrng = int(self.Vlims.value['xmax'])

            # Set the step
            if ringSel == '10 km':
                ringdel = 10
            if ringSel == '20 km':
                ringdel = 20
            if ringSel == '30 km':
                ringdel = 30
            if ringSel == '50 km':
                ringdel = 50
            if ringSel == '100 km':
                ringdel = 100

            # Calculate an array of range rings
            self.RNG_RINGS = range(ringdel, unrng, ringdel)

        self._update_plot()

    def cmapSelectCmd(self, cm_name):
        '''Captures colormap selection and redraws.'''
        CMAP = cm_name
        self.Vcmap.value['cmap'] = cm_name
        self.Vcmap.update()

    def toolZoomPanCmd(self):
        '''Creates and connects to a Zoom/Pan instance.'''
        from .tools import ZoomPan
        scale = 1.1
        self.tools['zoompan'] = ZoomPan(
            self.Vlims, self.ax,
            base_scale=scale, parent=self.parent)
        self.tools['zoompan'].connect()

    def toolValueClickCmd(self):
        '''Creates and connects to Point-and-click value retrieval'''
        from .tools import ValueClick
        self.tools['valueclick'] = ValueClick(
            self.Vradar, self.Vtilt, self.Vfield,
            self.units, self.ax, self.statusbar, parent=self.parent)
        self.tools['valueclick'].connect()

    def toolSelectRegionCmd(self):
        '''Creates and connects to Region of Interest instance'''
        from .select_region import SelectRegion
        self.tools['select_region'] = SelectRegion(
            self, name=self.name + " SelectRegion", parent=self)

    def toolResetCmd(self):
        '''Reset tools via disconnect.'''
        from . import tools
        self.tools = tools.reset_tools(self.tools)

    def toolDefaultCmd(self):
        '''Restore the Display defaults.'''
        from . import tools
        self.tools, limits, cmap = tools.restore_default_display(
            self.tools, self.Vfield.value, self.plot_type)
        self.Vcmap.change(cmap)
        self.Vlims.change(limits)

    def getPathInteriorValues(self, path):
        '''
        Return the bins values path.

        Parameters
        ----------
        path : Matplotlib Path instance

        Returns
        -------
        points: Points
            Points object containing all bins of the current radar
            and tilt inside path. Axes : 'x_disp', 'y_disp', 'ray_index',
            'range_index', 'azimuth', 'range'. Fields: just current field

        Notes
        -----
            If Vradar.value is None, returns None
        '''
        from .tools import interior_radar
        radar = self.Vradar.value
        if radar is None:
            return None

        xy, idx = interior_radar(path, radar, self.Vtilt.value)
        xaxis = {'data':  xy[:, 0] * 1000.,
                 'long_name': 'X-coordinate in Cartesian system',
                 'axis': 'X',
                 'units': 'm'}

        yaxis = {'data':  xy[:, 1] * 1000.,
                 'long_name': 'Y-coordinate in Cartesian system',
                 'axis': 'Y',
                 'units': 'm'}

        azi = radar.azimuth.copy()
        azi['data'] = radar.azimuth['data'][idx[:, 0]]

        rng = radar.range.copy()
        rng['data'] = radar.range['data'][idx[:, 1]]

        field = radar.fields[self.Vfield.value].copy()
        field['data'] = radar.fields[self.Vfield.value]['data'][
            idx[:, 0], idx[:, 1]]

        ray_idx = {'data': idx[:, 0],
                   'long_name': 'index in ray dimension'}
        rng_idx = {'data': idx[:, 1],
                   'long_name': 'index in range dimension'}

        axes = {'x_disp': xaxis,
                'y_disp': yaxis,
                'ray_index': ray_idx,
                'range_index': rng_idx,
                'azimuth': azi,
                'range': rng}

        fields = {self.Vfield.value: field}

        points = Points(fields, axes, radar.metadata.copy(), xy.shape[0])

        return points

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 8
        self.YSIZE = 8
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])
        self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
        # self._update_axes()

    def _update_fig_ax(self):
        '''Set the figure and axis to plot.'''
        if self.plot_type in ("radarAirborne", "radarRhi"):
            self.YSIZE = 5
        else:
            self.YSIZE = 8
        xwidth = 0.7
        yheight = 0.7  # * float(self.YSIZE) / float(self.XSIZE)
        self.ax.set_position([0.2, 0.55-0.5*yheight, xwidth, yheight])
        self.cax.set_position([0.2, 0.10, xwidth, 0.02])
        self._update_axes()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 7, 6)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''

        if self.Vradar.value is None:
            return

        # Create the plot with PyArt RadarDisplay
        self.ax.cla()  # Clear the plot axes
        self.cax.cla()  # Clear the colorbar axes

        if self.Vfield.value not in self.Vradar.value.fields.keys():
            self.canvas.draw()
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(255,0,0,255);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.showMessage("Field not Found in Radar", msecs=5000)
            return
        else:
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(0,0,0,0);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.clearMessage()

        title = self.title
        limits = self.Vlims.value
        cmap = self.Vcmap.value
        if self.gatefilterToggle.isChecked():
            gatefilter = self.Vgatefilter.value
        else:
            gatefilter = None

        if self.plot_type == "radarAirborne":
            self.display = pyart.graph.RadarDisplay_Airborne(self.Vradar.value)

            self.plot = self.display.plot_sweep_grid(
                self.Vfield.value, vmin=cmap['vmin'],
                vmax=cmap['vmax'], colorbar_flag=False, cmap=cmap['cmap'],
                mask_outside=True,
                gatefilter=gatefilter, ax=self.ax, fig=self.fig, title=title)
            self.display.plot_grid_lines()

        elif self.plot_type == "radarPpi":
            self.display = pyart.graph.RadarDisplay(self.Vradar.value)
            # Create Plot
            self.plot = self.display.plot_ppi(
                self.Vfield.value, self.Vtilt.value,
                vmin=cmap['vmin'], vmax=cmap['vmax'],
                colorbar_flag=False, cmap=cmap['cmap'], mask_outside=True,
                gatefilter=gatefilter, ax=self.ax, fig=self.fig, title=title)
            # Add range rings
            if self.RngRing:
                self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)
            # Add radar location
            self.display.plot_cross_hair(5., ax=self.ax)

        elif self.plot_type == "radarRhi":
            self.display = pyart.graph.RadarDisplay(self.Vradar.value)
            # Create Plot
            self.plot = self.display.plot_rhi(
                self.Vfield.value, self.Vtilt.value,
                vmin=cmap['vmin'], vmax=cmap['vmax'],
                colorbar_flag=False, cmap=cmap['cmap'], mask_outside=True,
                gatefilter=gatefilter, ax=self.ax, fig=self.fig, title=title)
            # Add range rings
            if self.RngRing:
                self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)

        self._update_axes()
        norm = mlabNormalize(vmin=cmap['vmin'],
                             vmax=cmap['vmax'])
        self.cbar = mlabColorbarBase(self.cax, cmap=cmap['cmap'],
                                     norm=norm, orientation='horizontal')
        self.cbar.set_label(self.units)

#        print "Plotting %s field, Tilt %d in %s" % (
#            self.Vfield.value, self.Vtilt.value+1, self.name)
        self.canvas.draw()

    def _update_axes(self):
        '''Change the Plot Axes.'''
        limits = self.Vlims.value
        self.ax.set_xlim(limits['xmin'], limits['xmax'])
        self.ax.set_ylim(limits['ymin'], limits['ymax'])
        self.ax.figure.canvas.draw()

    #########################
    # Check methods #
    #########################

    def _check_file_type(self):
        '''Check file to see if the file is airborne or rhi.'''
        radar = self.Vradar.value
        old_plot_type = self.plot_type
        if radar.scan_type != 'rhi':
            self.plot_type = "radarPpi"
        else:
            if 'platform_type' in radar.metadata:
                if (radar.metadata['platform_type'] == 'aircraft_tail' or
                        radar.metadata['platform_type'] == 'aircraft'):
                    self.plot_type = "radarAirborne"
                else:
                    self.plot_type = "radarRhi"
            else:
                self.plot_type = "radarRhi"

        if self.plot_type != old_plot_type:
            print("Changed Scan types, reinitializing")
            self._set_default_limits()
            self._update_fig_ax()

    def _set_default_limits(self, strong=True):
        ''' Set limits to pre-defined default.'''
        from .limits import _default_limits
        limits, cmap = _default_limits(
            self.Vfield.value, self.plot_type)
        self.Vlims.change(limits, strong)

    def _set_default_cmap(self, strong=True):
        ''' Set colormap to pre-defined default.'''
        cmap = pyart.config.get_field_colormap(self.Vfield.value)
        d = {}
        d['cmap'] = cmap
        lims = pyart.config.get_field_limits(self.Vfield.value,
                                             self.Vradar.value,
                                             self.Vtilt.value)
        if lims != (None, None):
            d['vmin'] = lims[0]
            d['vmax'] = lims[1]
        else:
            d['vmin'] = -10
            d['vmax'] = 65
        self.Vcmap.change(d, strong)

    def _get_default_title(self):
        '''Get default title from pyart.'''
        if (self.Vradar.value is None or
            self.Vfield.value not in self.Vradar.value.fields):
            return ''
        return pyart.graph.common.generate_title(self.Vradar.value,
                                                 self.Vfield.value,
                                                 self.Vtilt.value)

    def _get_default_units(self):
        '''Get default units for current radar and field.'''
        if self.Vradar.value is not None:
            try:
                return self.Vradar.value.fields[self.Vfield.value]['units']
            except:
                return ''
        else:
            return ''

    ########################
    # Image save methods #
    ########################
    def _quick_savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display via PyArt interface.'''
        imagename = self.display.generate_filename(
            self.Vfield.value, self.Vtilt.value, ext=IMAGE_EXT)
        self.canvas.print_figure(os.path.join(os.getcwd(), imagename), dpi=DPI)
        self.statusbar.showMessage(
            'Saved to %s' % os.path.join(os.getcwd(), imagename))

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        PBNAME = self.display.generate_filename(
            self.Vfield.value, self.Vtilt.value, ext=IMAGE_EXT)
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', PBNAME, file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)

    ########################
    #      get methods     #
    ########################

    def getPlotAxis(self):
        '''Get :py:class:`matplotlib.axes.Axes` instance of main plot.'''
        return self.ax

    def getStatusBar(self):
        '''Get :py:class:`PyQt4.QtGui.QStatusBar` instance.'''
        return self.statusbar

    def getField(self):
        '''Get current field.'''
        return self.Vfield.value

    def getUnits(self):
        '''Get current units.'''
        return self.units
        
    def getRadar(self):
        ''' get current radar '''
        return self.Vradar.value
예제 #18
0
def plot_data_products():

    # Define all bounds first s.t. we can draw the context boxes on the
    # dechirped image.

    # The raw bounds are for the full image
    raw_min_sample = 150
    raw_max_sample = 2300
    raw_bounds = [0, 9075, raw_min_sample, raw_max_sample]

    # The filtering needs to zoom in on the surface
    filter_bounds = [1700, 5900, 425, 650]

    # For the SNR improvements of incoherent stacking, look at the layers that just pop out.
    layer_bounds = [7400, 8580, 200, 1750]
    # For filtered, clim = [110000, 195000] and for stacked, clim=[140000, 225000]

    # Zooming in on the crevasses shows speckle nicely
    incoherent_bounds = [2880, 4900, 850, 1700]
    #The clim for this is best is the coherent is [150000, 234000] and incoherent is [160000, 234000]

    # Appropriate color limits depend on the processing used
    raw_clim = [25000, 90000]
    dechirped_clim = [115000, 200000]
    filtered_clim = [115000, 200000]

    # First, generate the raw figure that requires raw data + dechirped data
    # over the full transect.
    raw_shape = (50, 17)
    #raw_shape = (10, 17./5) # This is ugly ...

    # fig_raw = Figure(raw_shape, dpi=150)
    # canvas_raw = FigureCanvas(fig_raw)
    # ax_raw = fig_raw.add_axes([0, 0, 1, 1])
    # ax_raw.axis('off')
    # plot_radar(ax_raw, 'TOT_raw', 3200, raw_bounds, raw_clim)
    # canvas_raw.print_figure('../FinalReport/figures/TOT_raw_full.jpg')

    multiple_bounds = [3050, 5325, 325, 2675]
    fig_multiples = Figure(raw_shape, dpi=150)
    canvas_multiples = FigureCanvas(fig_multiples)
    ax_multiples = fig_multiples.add_axes([0, 0, 1, 1])
    ax_multiples.axis('off')
    plot_radar(ax_multiples,
               'TOT_no_blanking',
               3200,
               multiple_bounds,
               clim=[140000, 230000])
    ax_multiples.text(3950,
                      900,
                      'surface multiple',
                      color='red',
                      fontsize=70,
                      horizontalalignment='left',
                      verticalalignment='bottom')
    ax_multiples.text(3950,
                      2380,
                      'basal multiple',
                      color='red',
                      fontsize=70,
                      horizontalalignment='left',
                      verticalalignment='top')
    canvas_multiples.print_figure('../FinalReport/figures/TOT_multiples.jpg')
class FlowEstimatorDialog(QtGui.QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        super(FlowEstimatorDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        #QDialog.__init__(self, None, Qt.WindowStaysOnTopHint)
        self.iface = iface
        self.setupUi(self)

        self.btnOk = self.buttonBox.button(QtGui.QDialogButtonBox.Ok)
        self.btnOk.setText("Save Data")
        self.btnClose = self.buttonBox.button(QtGui.QDialogButtonBox.Close)
        self.btnBrowse.clicked.connect(self.writeDirName)
        self.btnLoadTXT.clicked.connect(self.loadTxt)
        self.btnSampleLine.setEnabled(False)
        self.btnSampleSlope.setEnabled(False)
        self.calcType = 'Trap'

        # add matplotlib figure to dialog
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.figure.subplots_adjust(left=.1,
                                    bottom=0.15,
                                    right=.78,
                                    top=.9,
                                    wspace=None,
                                    hspace=.2)
        self.mplCanvas = FigureCanvas(self.figure)

        #self.widgetPlotToolbar = NavigationToolbar(self.mplCanvas, self.widgetPlot)
        #lstActions = self.widgetPlotToolbar.actions()
        #self.widgetPlotToolbar.removeAction(lstActions[7])
        self.vLayout.addWidget(self.mplCanvas)
        self.vLayout.minimumSize()
        #self.vLayout.addWidget(self.widgetPlotToolbar)
        self.figure.patch.set_visible(False)

        # and configure matplotlib params
        #        rcParams["font.serif"] = "Verdana, Arial, Liberation Serif"
        #        rcParams["font.sans-serif"] = "Tahoma, Arial, Liberation Sans"
        #        rcParams["font.cursive"] = "Courier New, Arial, Liberation Sans"
        #        rcParams["font.fantasy"] = "Comic Sans MS, Arial, Liberation Sans"
        #        rcParams["font.monospace"] = "Courier New, Liberation Mono"
        #
        #print self.cbDEM.changeEvent
        self.depth.valueChanged.connect(self.run)
        self.botWidth.valueChanged.connect(self.run)
        self.leftSS.valueChanged.connect(self.run)
        self.rightSS.valueChanged.connect(self.run)
        self.n.valueChanged.connect(self.run)
        self.slope.valueChanged.connect(self.run)
        self.cbWSE.valueChanged.connect(self.run)
        self.ft.clicked.connect(self.run)
        self.m.clicked.connect(self.run)
        self.cbUDwse.valueChanged.connect(self.run)

        self.manageGui()

        self.btnSampleLine.clicked.connect(self.sampleLine)
        self.btnSampleSlope.clicked.connect(self.sampleSlope)

    def manageGui(self):
        print 'manageGui'
        self.cbDEM.clear()
        if utils.getRasterLayerNames():
            self.cbDEM.addItems(utils.getRasterLayerNames())
            self.btnSampleLine.setEnabled(True)
            self.btnSampleSlope.setEnabled(True)
        self.run()

#    def refreshPlot(self):
#        self.axes.clear()

    def plotter(self):

        R, area, topWidth, Q, v, depth, xGround, yGround, yGround0, xWater, yWater, yWater0 = self.args
        self.axes.clear()
        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.plot(xGround, yGround, 'k')
        #self.axes.fill_between(xGround, yGround, yGround0, where=yGround>yGround0, facecolor='0.9', interpolate=True)
        if Q != 0:
            self.axes.plot(xWater, yWater, 'blue')
            self.axes.fill_between(xWater,
                                   yWater,
                                   yWater0,
                                   where=yWater >= yWater0,
                                   facecolor='blue',
                                   interpolate=True,
                                   alpha=0.1)
        self.outText = 'R: {0:.2f} {5}\nArea: {1:,.2f} {5}$^2$\nTop Width: {2:.2f} {5}\nDepth: {6:,.2f} {5}\nQ: {3:,.2f} {5}$^3$/s\nVelocity {4:,.2f} {5}/s'.format(
            R, area, topWidth, Q, v, self.units, depth)
        self.axes.set_xlabel('Station, ' + self.units)
        self.axes.set_ylabel('Elevation, ' + self.units)
        self.axes.set_title('Cross Section')
        #self.axes.set_ylim(bottom=0)
        #self.axes.show()

        #print self.outText
        self.refreshPlotText()

    def refreshPlotText(self):

        self.axes.annotate(self.outText,
                           xy=(.8, .35),
                           xycoords='figure fraction')
        #at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
        #self.axes.add_artist(at)
        self.mplCanvas.draw()

    def run(self):
        if self.ft.isChecked():
            self.units = 'ft'
        else:
            self.units = 'm'

        if self.tabWidget.currentIndex() == 0:
            print 'calc trap channel'
            self.calcType = 'Trap'
            self.args = flowEstimator(self.depth.value(),
                                      self.n.value(),
                                      self.slope.value(),
                                      widthBottom=self.botWidth.value(),
                                      rightSS=self.rightSS.value(),
                                      leftSS=self.leftSS.value(),
                                      units=self.units)
            self.plotter()
        elif self.tabWidget.currentIndex() == 1:
            try:
                self.calcType = 'DEM'
                #                print self.cbWSE.value(), self.n.value(), self.slope.value(), self.staElev, self.units
                self.args = flowEstimator(self.cbWSE.value(),
                                          self.n.value(),
                                          self.slope.value(),
                                          staElev=self.staElev,
                                          units=self.units)
                self.plotter()
            except:
                self.axes.clear()
        else:

            try:
                self.calcType = 'UD'
                self.args = flowEstimator(self.cbUDwse.value(),
                                          self.n.value(),
                                          self.slope.value(),
                                          staElev=self.staElev,
                                          units=self.units)
                self.plotter()
            except:
                self.axes.clear()

    def sampleLine(self):
        try:
            self.deactivate()
        except:
            pass
        self.btnSampleLine.setEnabled(False)
        self.sampleBtnCode = 'sampleLine'
        self.rubberBand()

    def sampleSlope(self):
        try:
            self.deactivate()
        except:
            pass
        self.btnSampleSlope.setEnabled(False)
        self.sampleBtnCode = 'sampleSlope'
        self.rubberBand()
#==============================================================================
# START rubberband and related functions from
#       https://github.com/etiennesky/profiletool
#==============================================================================

    def rubberBand(self):

        print 'rubberband '
        self.canvas = self.iface.mapCanvas()
        #Init classe variables
        if self.sampleBtnCode == 'sampleLine':
            self.tool = ProfiletoolMapTool(
                self.canvas, self.btnSampleLine)  #the mouselistener
        else:
            self.tool = ProfiletoolMapTool(
                self.canvas, self.btnSampleSlope)  #the mouselistener
        self.pointstoDraw = None  #Polyline in mapcanvas CRS analysed
        self.dblclktemp = False  #enable disctinction between leftclick and doubleclick
        self.selectionmethod = 0  #The selection method defined in option
        self.saveTool = self.canvas.mapTool(
        )  #Save the standard mapttool for restoring it at the end
        self.textquit0 = "Click for polyline and double click to end (right click to cancel then quit)"
        self.textquit1 = "Select the polyline in a vector layer (Right click to quit)"
        #Listeners of mouse
        self.connectTool()
        #init the mouse listener comportement and save the classic to restore it on quit
        self.canvas.setMapTool(self.tool)
        #init the temp layer where the polyline is draw
        self.polygon = False
        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        self.rubberband.setWidth(2)
        if self.sampleBtnCode == 'sampleLine':
            color = Qt.red
        else:
            color = Qt.blue
        self.rubberband.setColor(QColor(color))
        #init the table where is saved the poyline
        self.pointstoDraw = []
        self.pointstoCal = []
        self.lastClicked = [[-9999999999.9, 9999999999.9]]
        # The last valid line we drew to create a free-hand profile
        self.lastFreeHandPoints = []
        #Help about what doing
        if self.selectionmethod == 0:
            self.iface.mainWindow().statusBar().showMessage(self.textquit0)
        elif self.selectionmethod == 1:
            self.iface.mainWindow().statusBar().showMessage(self.textquit1)

    #************************************* Mouse listener actions ***********************************************

    def moved(self,
              position):  #draw the polyline on the temp layer (rubberband)
        #print 'moved'
        if self.selectionmethod == 0:
            if len(self.pointstoDraw) > 0:
                #Get mouse coords
                mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
                    position["x"], position["y"])
                #Draw on temp layer
                if QGis.QGIS_VERSION_INT >= 10900:
                    self.rubberband.reset(QGis.Line)
                else:
                    self.rubberband.reset(self.polygon)
                for i in range(0, len(self.pointstoDraw)):
                    self.rubberband.addPoint(
                        QgsPoint(self.pointstoDraw[i][0],
                                 self.pointstoDraw[i][1]))
                self.rubberband.addPoint(QgsPoint(mapPos.x(), mapPos.y()))
#        if self.selectionmethod == 1:
#            return

    def rightClicked(self, position):  #used to quit the current action
        print 'rightclicked'
        if self.selectionmethod == 0:
            if len(self.pointstoDraw) > 0:
                self.pointstoDraw = []
                self.pointstoCal = []
                self.rubberband.reset(self.polygon)
            else:
                self.cleaning()

    def leftClicked(self, position):  #Add point to analyse
        print 'leftclicked'
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
            position["x"], position["y"])
        newPoints = [[mapPos.x(), mapPos.y()]]
        if self.selectionmethod == 0:
            if newPoints == self.dblclktemp:
                self.dblclktemp = None
                return
            else:
                if len(self.pointstoDraw) == 0:
                    self.rubberband.reset(self.polygon)
                self.pointstoDraw += newPoints

    def doubleClicked(self, position):
        print 'doubleclicked'
        if self.selectionmethod == 0:
            #Validation of line
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
                position["x"], position["y"])
            newPoints = [[mapPos.x(), mapPos.y()]]
            self.pointstoDraw += newPoints
            #launch analyses
            self.iface.mainWindow().statusBar().showMessage(
                str(self.pointstoDraw))

            if self.sampleBtnCode == 'sampleLine':
                self.staElev, error = self.doRubberbandProfile()
                if error:
                    self.deactivate()
                else:
                    self.doIrregularProfileFlowEstimator()
                self.btnSampleLine.setEnabled(True)
                self.deactivate()
            else:
                staElev, error = self.doRubberbandProfile()
                if error:
                    self.deactivate()
                else:
                    self.doRubberbandSlopeEstimator(staElev)
                self.btnSampleSlope.setEnabled(True)
                self.deactivate()

            #Reset
            self.lastFreeHandPoints = self.pointstoDraw
            self.pointstoDraw = []
            #temp point to distinct leftclick and dbleclick
            self.dblclktemp = newPoints
            self.iface.mainWindow().statusBar().showMessage(self.textquit0)
            self.iface.mainWindow().activateWindow()
            return

###***********************************************

    def connectTool(self):
        print 'connecting'
        QObject.connect(self.tool, SIGNAL("moved"), self.moved)
        #        self.tool.moved.connect(self.moved)
        QObject.connect(self.tool, SIGNAL("rightClicked"), self.rightClicked)
        QObject.connect(self.tool, SIGNAL("leftClicked"), self.leftClicked)
        QObject.connect(self.tool, SIGNAL("doubleClicked"), self.doubleClicked)
        QObject.connect(self.tool, SIGNAL("deactivate"), self.deactivate)

    def deactivate(self):  #enable clean exit of the plugin
        self.cleaning()
        QObject.disconnect(self.tool, SIGNAL("moved"), self.moved)
        QObject.disconnect(self.tool, SIGNAL("leftClicked"), self.leftClicked)
        QObject.disconnect(self.tool, SIGNAL("rightClicked"),
                           self.rightClicked)
        QObject.disconnect(self.tool, SIGNAL("doubleClicked"),
                           self.doubleClicked)
#        self.rubberband.reset(self.polygon)
#        self.iface.mainWindow().statusBar().showMessage("")

#        self.depth.setEnabled(True)
#        self.botWidth.setEnabled(True)
#        self.leftSS.setEnabled(True)
#        self.rightSS.setEnabled(True)
#        self.n.setEnabled(True)
#        self.slope.setEnabled(True)
#        self.cbWSE.setEnabled(True)
#        self.ft.setEnabled(True)
#        self.m.setEnabled(True)
#        self.cbDEM.setEnabled(True)

    def cleaning(self):  #used on right click
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.saveTool)
        self.rubberband.reset(self.polygon)
        #self.rubberband.reset(self.polygon)
        self.iface.mainWindow().statusBar().showMessage("")
#==============================================================================
# END rubberband and related functions from
#       https://github.com/etiennesky/profiletool
#==============================================================================

    def doRubberbandProfile(self):
        layerString = self.cbDEM.currentText()
        layer = utils.getRasterLayerByName(' '.join(
            layerString.split(' ')[:-1]))
        if layer.isValid():
            self.xRes = layer.rasterUnitsPerPixelX()
        line = LineString(self.pointstoDraw[:-1])
        xyzdList = utils.elevationSampler(line, self.xRes, layer)
        sta = xyzdList[-1]
        elev = xyzdList[-2]
        staElev = np.array(zip(sta, elev))
        try:
            np.isnan(np.sum(staElev[:, 1]))
            return [staElev, None]
        except:
            QMessageBox.warning(self, 'Error',
                                'Sampled line not within bounds of DEM')
            #self.cleaning()

            return [staElev, 'error']

    def doIrregularProfileFlowEstimator(self):
        thalweig = self.staElev[np.where(
            self.staElev[:, 1] == np.min(self.staElev[:, 1]))]
        thalweigX = thalweig[:, 0][0]
        minElev = thalweig[:, 1][0] + .01
        try:
            lbMaxEl = self.staElev[np.where(
                self.staElev[:, 0] > thalweigX)][:, 1].max()
        except:
            QMessageBox.warning(self, 'Error', 'Channel not found')
            try:
                self.deactivate()
            except:
                pass
            return
        try:
            rbMaxEl = self.staElev[np.where(
                self.staElev[:, 0] < thalweigX)][:, 1].max()
        except:
            QMessageBox.warning(self, 'Error', 'Channel not found')
            try:
                self.deactivate()
            except:
                pass
            return
        maxElev = np.array([lbMaxEl, rbMaxEl]).min() - .01
        WSE = maxElev
        WSE = (self.staElev[:, 1].max() -
               self.staElev[:, 1].min()) / 2. + self.staElev[:, 1].min()
        if self.tabWidget.currentIndex() == 1:
            self.cbWSE.setValue(WSE)
            self.cbWSE.setMinimum(minElev)
            self.cbWSE.setMaximum(maxElev)
        elif self.tabWidget.currentIndex() == 2:
            self.cbUDwse.setValue(WSE)
            self.cbUDwse.setMinimum(minElev)
            self.cbUDwse.setMaximum(maxElev)
        else:
            return

        self.run()

    def doRubberbandSlopeEstimator(self, staElev):

        slope = -(staElev[:, 1][-1] - staElev[:, 1][0]) / staElev[:, 0][-1]
        print slope

        self.axes.clear()

        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.plot(staElev[:, 0], staElev[:, 1], 'k', label='Sampled DEM')
        x = np.array([staElev[0, 0], staElev[-1, 0]])
        y = np.array([staElev[0, 1], staElev[-1, 1]])
        self.axes.plot(x, y, label='Slope')
        self.axes.set_xlabel('Station, ' + self.units)
        self.axes.set_ylabel('Elevation, ' + self.units)
        self.axes.set_title('DEM Derived Slope = ' + slope.astype('|S8'))
        self.axes.legend()
        self.mplCanvas.draw()
        if slope <= 0:
            QMessageBox.warning(
                self, 'Error',
                'Negative or zero slope\nPlease check sampled area\n\nWater flows downhill you know!'
            )
            print 'error: negative slope'
        else:
            reply = QMessageBox.question(
                self, 'Message',
                'DEM Derived Slope is {}\nWould you like to use this value?'.
                format(slope.astype('|S8')), QMessageBox.Yes | QMessageBox.No,
                QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.slope.setValue(slope)

            else:
                pass

    def writeDirName(self):
        self.outputDir.clear()
        self.dirName = QFileDialog.getExistingDirectory(
            self, 'Select Output Directory')
        self.outputDir.setText(self.dirName)

    def loadTxt(self):
        filePath = QFileDialog.getOpenFileName(
            self,
            'Select tab or space delimited text file containing station and elevation data'
        )
        print filePath
        try:
            self.staElev = np.loadtxt(filePath)
            self.inputFile.setText(filePath)
            self.calcType = 'UD'
            self.doIrregularProfileFlowEstimator()
        except:
            QMessageBox.warning(
                self, 'Error',
                'Please check that the text file is space or tab delimited and does not contain header information'
            )

    def accept(self):
        # assign results to numpy array for quick csv dump
        outPath = self.outputDir.text()
        home = os.path.expanduser("~")
        if outPath == '':
            outPath = os.path.join(home, 'Desktop', 'QGIS2FlowEstimatorFiles')
            self.outputDir.setText(outPath)
            if not os.path.exists(outPath):
                os.makedirs(outPath)
        os.chdir(outPath)
        fileName = 'FlowEstimatorResults.txt'
        outFile = open(fileName, 'w')
        outHeader = '*' * 20 + '\nFlow Estimator - A QGIS plugin\nEstimates uniform, steady flow in a channel using Mannings equation\n' + '*' * 20
        if self.calcType == 'DEM':
            proj4 = utils.getRasterLayerByName(
                self.cbDEM.currentText().split(' EPSG')[0]).crs().toProj4()
            outHeader += '\n' * 5 + 'Type:\tCross Section from DEM\nUnits:\t{0}\nDEM Layer:\t{1}\nProjection (Proj4 format):\t{2}\nChannel Slope:\t{3:.06f}\nMannings n:\t{4:.02f}\n\n\n\nstation\televation\n'.format(
                self.units, self.cbDEM.currentText(), proj4,
                self.slope.value(), self.n.value())
            outFile.write(outHeader)
            np.savetxt(outFile, self.staElev, fmt='%.3f', delimiter='\t')
            wseMax = self.cbWSE.value()
            wseMin = self.cbWSE.minimum()
        elif self.calcType == 'UD':
            proj4 = utils.getRasterLayerByName(
                self.cbDEM.currentText().split(' EPSG')[0]).crs().toProj4()
            outHeader += '\n' * 5 + 'Type:\tUser Defined Cross Section\nUnits:\t{0}\nChannel Slope:\t{1:.06f}\nMannings n:\t{2:.02f}\n\n\n\nstation\televation\n'.format(
                self.units, self.slope.value(), self.n.value())
            outFile.write(outHeader)
            np.savetxt(outFile, self.staElev, fmt='%.3f', delimiter='\t')
            wseMax = self.cbUDwse.value()
            wseMin = self.cbUDwse.minimum()

        else:
            outHeader += '\n' * 5 + 'Type:\tTrapizodal Channel\nUnits:\t{0}\nChannel Slope:\t{1:.06f}\nMannings n:\t{2:.02f}\nBottom Width:\t{3:.02f}\nRight Side Slope:\t{4:.02f}\nLeft Side Slope:\t{5:.02f}\n'.format(
                self.units, self.slope.value(), self.n.value(),
                self.botWidth.value(), self.rightSS.value(),
                self.leftSS.value())
            outFile.write(outHeader)
            wseMax = self.depth.value()
            wseMin = 0.0
        self.mplCanvas.print_figure('FlowEstimatorResultsXSFigure')
        outHeader = '\n\n\n\n\n\n\nwater surface elevation\tflow\tvelocity\tR\tarea\ttop width\tdepth\n'
        outFile.write(outHeader)
        ###do loop here
        step = 0.1
        wseList = []
        qList = []
        for wse in utils.frange(wseMin, wseMax, step):
            if self.calcType == 'DEM' or self.calcType == 'UD':
                args = flowEstimator(wse,
                                     self.n.value(),
                                     self.slope.value(),
                                     staElev=self.staElev,
                                     units=self.units)
            else:
                args = flowEstimator(wse,
                                     self.n.value(),
                                     self.slope.value(),
                                     widthBottom=self.botWidth.value(),
                                     rightSS=self.rightSS.value(),
                                     leftSS=self.leftSS.value(),
                                     units=self.units)
            R, area, topWidth, Q, v, depth, xGround, yGround, yGround0, xWater, yWater, yWater0 = args
            data = '{0}\t{1:.02f}\t{2:.02f}\t{3:.02f}\t{4:.02f}\t{5:.02f}\t{6:.02f}\n'.format(
                wse, Q, v, R, area, topWidth, depth)
            outFile.write(data)
            wseList.append(wse)
            qList.append(Q)

        self.axes.clear()
        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)
        self.axes.plot(qList, wseList, 'k', label='Rating Curve')
        self.axes.set_ylabel('Water Surface Elevation, ' + self.units)
        self.axes.set_xlabel('Discharge, {0}$^3$/s'.format(self.units))
        self.axes.set_title('Rating Curve')
        self.axes.grid()
        self.mplCanvas.draw()
        self.mplCanvas.print_figure('FlowEstimatorRatingCurve')

        outFile.close()

        self.iface.messageBar().pushMessage(
            "Flow Estimator",
            'Output files located here {}.  Please delete when finished'.
            format(outPath),
            duration=30)
class DrainageChannelBuilderDialog(QtGui.QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        super(DrainageChannelBuilderDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.iface = iface
        self.setupUi(self)

        self.resWarning = False

        self.btnOk = self.buttonBox.button(QtGui.QDialogButtonBox.Ok)
        self.btnOk.setText(self.tr("Run 2D"))
        self.btnClose = self.buttonBox.button(QtGui.QDialogButtonBox.Close)

        self.cbDEM.currentIndexChanged.connect(self.updateRasterRes)
        self.cbDEM.currentIndexChanged.connect(self.checkLayerExtents)
        self.cbCL.currentIndexChanged.connect(self.checkLayerExtents)
        self.spinElevStart.valueChanged.connect(self.calcDepth)
        self.spinElevEnd.valueChanged.connect(self.calcDepth)
        self.spinRightSideSlope.valueChanged.connect(self.updateMaxBankWidth)
        self.spinLeftSideSlope.valueChanged.connect(self.updateMaxBankWidth)
        self.spinWidth.valueChanged.connect(self.checkRes)
        self.spinRes.valueChanged.connect(self.checkRes)
        self.browseBtn.clicked.connect(self.writeDirName)
        self.btn1Dsave.clicked.connect(self.writeOut1Dresults)

        # add matplotlib figure to dialog
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.figure.subplots_adjust(left=.1,
                                    bottom=0.1,
                                    right=.95,
                                    top=.9,
                                    wspace=None,
                                    hspace=.2)
        self.canvas = FigureCanvas(self.figure)

        self.widgetPlotToolbar = NavigationToolbar(self.canvas,
                                                   self.widgetPlot)
        lstActions = self.widgetPlotToolbar.actions()
        self.widgetPlotToolbar.removeAction(lstActions[7])
        self.gPlot.addWidget(self.canvas)
        self.gPlot.addWidget(self.widgetPlotToolbar)
        self.figure.patch.set_visible(False)

        # and configure matplotlib params
        rcParams["font.serif"] = "Verdana, Arial, Liberation Serif"
        rcParams["font.sans-serif"] = "Tahoma, Arial, Liberation Sans"
        rcParams["font.cursive"] = "Courier New, Arial, Liberation Sans"
        rcParams["font.fantasy"] = "Comic Sans MS, Arial, Liberation Sans"
        rcParams["font.monospace"] = "Courier New, Liberation Mono"

        self.manageGui()

    def manageGui(self):
        print 'manageGui'
        self.cbCL.clear()
        self.cbCL.addItems(utils.getLineLayerNames())
        self.cbDEM.clear()
        self.cbDEM.addItems(utils.getRasterLayerNames())

    def refreshPlot(self):
        self.axes.clear()

        results1D = utils.getPlotArray(self.vLayer, self.rLayer,
                                       self.spinElevStart.value(),
                                       self.spinElevEnd.value(), self.xRes)

        self.stationA = results1D[0, :]

        self.zExistA = results1D[1, :]
        self.zPropA = results1D[2, :]
        self.xA = results1D[3, :]
        self.yA = results1D[4, :]
        self.calcCutAvgAreaEndMeth()

        self.axes.plot(self.stationA, self.zExistA)
        self.axes.plot(self.stationA, self.zPropA)
        self.axes.grid()
        formatter = ScalarFormatter(useOffset=False)
        self.axes.yaxis.set_major_formatter(formatter)

        self.axes.set_ylabel(unicode(self.tr("Elevation, z field units")))
        self.axes.set_xlabel(unicode(self.tr('Station, layer units')))
        self.axes.set_title(
            unicode(
                self.tr('Channel {} Profile and 1D Calculation Results'.format(
                    self.vLayer.name()))))
        at = AnchoredText(
            self.outText,
            prop=dict(size=12),
            frameon=True,
            loc=1,
        )
        at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")

        self.axes.add_artist(at)
        self.canvas.draw()

    def refreshPlotText(self):

        at = AnchoredText(
            self.outText,
            prop=dict(size=12),
            frameon=True,
            loc=1,
        )
        at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
        self.axes.add_artist(at)
        self.canvas.draw()

    def calcCutAvgAreaEndMeth(self):
        self.depth1D = self.zExistA - self.zPropA

        # find max bank width based on CL depth
        self.maxCLdepth = np.max(self.depth1D)
        leftSlope = self.spinLeftSideSlope.value()
        rightSlope = self.spinRightSideSlope.value()
        width = self.spinWidth.value()
        self.area = self.depth1D * (width + self.depth1D * leftSlope / 2.0 +
                                    self.depth1D * rightSlope / 2.0)
        self.length = self.stationA[1:] - self.stationA[:-1]
        self.vol1D = (self.area[1:] + self.area[:-1]) * self.length / 2.0
        self.vol1D = np.append(0, self.vol1D)
        self.totVol1D = np.sum(self.vol1D)
        self.maxDepth1D = np.max(self.depth1D)
        self.totLength = np.max(self.stationA)
        self.channelSlope = (self.zPropA[-1] - self.zPropA[0]) / self.totLength
        self.outText = 'Length: {2:.2f} layer units\nChannel Slope: {3:.6f}\n1D Max. Cut Depth: {0:,.2f} layer units\n1D Tot. Vol.: {1:,.2f} layer units$^3$'.format(
            self.maxDepth1D, self.totVol1D, self.totLength, self.channelSlope)

        #self.canvas.draw()

    def writeOut1Dresults(self):
        # assign results to numpy array for quick csv dump
        self.out1Dresults = np.zeros((self.stationA.size, 8))
        self.out1Dresults[:, 0] = self.stationA
        self.out1Dresults[:, 1] = self.vol1D
        self.out1Dresults[:, 2] = self.zExistA
        self.out1Dresults[:, 3] = self.zPropA
        self.out1Dresults[:, 4] = self.depth1D
        self.out1Dresults[:, 5] = self.area
        self.out1Dresults[:, 6] = self.xA
        self.out1Dresults[:, 7] = self.yA
        outPath = self.outputDir.text()
        home = os.path.expanduser("~")
        if outPath == '':
            outPath = os.path.join(home, 'Desktop',
                                   'QGIS2DrainageChannelBuilderFiles')
            self.outputDir.setText(outPath)
            if not os.path.exists(outPath):
                os.makedirs(outPath)

        os.chdir(outPath)
        fileName = 'Channel1Dresults_{}.txt'.format(self.vLayer.name())
        outHeader = 'DEM Layer:\t{0}\nChannel Centerline:\t{1}\nProjection (Proj4 format):\t{13}\nChannel Bottom Width:\t{3}\nChannel Start Elevation:\t{4}\nChannel End Elevation:\t{5}\nChannel Slope:\t{12:.06f}\nLeft Side Slope:\t{6}\nRight Side Slope:\t{7}\nLength:\t{9:,.2f}\n1D Max. Cut Depth:\t{10:,.2f}\n1D Tot. Vol:\t{11:,.2f}\nNote:\tAll units of length correspond to layer units, all units of area and volume are a combination of layer units and raster elevation units\n\nstation\tvol\tzExist\tzProp\tdepth\tcutArea\tx\ty\n'.format(
            self.cbDEM.currentText(), self.cbCL.currentText(),
            self.spinRes.value(), self.spinWidth.value(),
            self.spinElevStart.value(), self.spinElevEnd.value(),
            self.spinLeftSideSlope.value(), self.spinRightSideSlope.value(),
            self.spinBankWidth.value(), self.totLength, self.maxDepth1D,
            self.totVol1D, self.channelSlope,
            self.rLayer.crs().toProj4())
        np.savetxt(fileName,
                   self.out1Dresults,
                   fmt='%.3f',
                   header=outHeader,
                   delimiter='\t')
        self.canvas.print_figure('Channel1DresultsFigure_{}'.format(
            self.vLayer.name()))

    def updateMaxBankWidth(self):

        self.maxBankWidth = self.maxCLdepth * np.max(
            np.array([
                self.spinLeftSideSlope.value(),
                self.spinRightSideSlope.value()
            ]))
        self.spinBankWidth.setValue(self.maxBankWidth +
                                    self.spinRes.value() / 2.)
        self.calcCutAvgAreaEndMeth()
        self.refreshPlotText()

    def writeDirName(self):
        self.outputDir.clear()
        self.dirName = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select Output Directory')
        self.outputDir.setText(self.dirName)
        self.checkBoxLoadLayers.setCheckState(True)

    def updateRasterRes(self):

        layer = utils.getRasterLayerByName(
            self.cbDEM.currentText().split(' EPSG')[0])
        if layer.isValid():
            self.xRes = layer.rasterUnitsPerPixelX()
            self.yRes = layer.rasterUnitsPerPixelY()
            self.labelDEMres.setText(
                'DEM Layer Resolution = {:.2f} X {:.2f} Y'.format(
                    self.xRes, self.yRes))

    def checkRes(self):

        if self.spinWidth.value() <= self.spinRes.value() * 10:

            self.resWarning = True
            self.errOutput()
        else:
            self.resWarning = False
            self.errOutput()
        self.calcCutAvgAreaEndMeth()
        self.refreshPlotText()

    def checkLayerExtents(self):

        self.rLayer = utils.getRasterLayerByName(
            self.cbDEM.currentText().split(' EPSG')[0])
        self.vLayer = utils.getVectorLayerByName(
            self.cbCL.currentText().split(' EPSG')[0])
        try:
            if self.rLayer.isValid() and self.vLayer.isValid():
                if self.rLayer.extent().xMaximum() >= self.vLayer.extent(
                ).xMaximum() and self.rLayer.extent().xMinimum(
                ) <= self.vLayer.extent().xMinimum() and self.rLayer.extent(
                ).yMaximum() >= self.vLayer.extent().yMaximum(
                ) and self.rLayer.extent().yMinimum() <= self.vLayer.extent(
                ).yMinimum():
                    self.layersOverlap = True
                    self.calcElev()
                    self.btn1Dsave.setEnabled(True)
                    self.btnOk.setEnabled(True)
                    self.errOutput()

                else:
                    self.btnOk.setEnabled(False)
                    self.spinElevStart.setEnabled(False)
                    self.spinElevEnd.setEnabled(False)
                    self.layersOverlap = False
                    self.errOutput()
        except:
            self.btnOk.setEnabled(False)
            self.spinElevStart.setEnabled(False)
            self.spinElevEnd.setEnabled(False)
            self.btn1Dsave.setEnabled(False)
            self.overlayError = True
            self.layersOverlap = False
            self.errOutput()
            pass

    def calcDepth(self):
        if self.layersOverlap:

            self.layersOverlap = utils.calcDepth(self)
        if self.layersOverlap:
            self.refreshPlot()

    def calcElev(self):
        if self.layersOverlap:
            self.spinElevStart.setEnabled(True)
            self.spinElevEnd.setEnabled(True)
            self.spinElevStart.setValue(utils.calcElev(self)[0])
            self.spinElevEnd.setValue(utils.calcElev(self)[1])
            self.refreshPlot()

    def updateProgressText(self, message):
        self.labelProgress.setText(message)

    def updateOutputText(self, message):
        self.textBrowser.setPlainText(message)

    def workerError(self, e, exception_string):
        print 'workerError\n{}\n'.format(exception_string)
        QgsMessageLog.logMessage(
            'Worker thread raised an exception:\n{}'.format(exception_string),
            level=QgsMessageLog.CRITICAL)
        self.iface.messageBar().pushMessage(
            "Drainge Channel Builder",
            'It didnt work, see log for details',
            level=QgsMessageBar.CRITICAL,
            duration=3)
        self.progressBar.setMaximum(100)
        self.btnOk.setEnabled(True)
        self.btn1Dsave.setEnabled(True)

    def stopWorker(self):
        self.worker.kill()
        if self.worker is not None:

            self.worker.deleteLater()
            self.thread.quit()
            self.thread.wait()
            self.thread.deleteLater()

    def errOutput(self):
        if self.resWarning and not self.layersOverlap:
            self.labelErrMessage.setText(
                'Error: Vector is not completely within raster domain\nWarning: For best 2D results, channel bottom width should be at least ten times greater than 2D grid calculation resolution'
            )
        elif self.resWarning:
            self.labelErrMessage.setText(
                'Warning: For best 2D results, channel bottom width should be at least ten times greater than 2D grid calculation resolution'
            )
        elif not self.layersOverlap:
            self.labelErrMessage.setText(
                'Error: Vector is not completely within raster domain')
        else:
            self.labelErrMessage.setText('')

    def workerFinished(self, values):
        # print 'values = ',values
        self.stopWorker()
        self.values = values
        maxCut = values[0][0]
        avgCut = values[0][1]
        totVol = values[0][2]
        self.dirName = values[0][3]
        self.outputDir.setText(self.dirName)
        demChannelPath = values[0][4]
        demCutDepth = values[0][5]
        length = values[0][6]
        outText = 'Summary of 2D Results:\nTot. Vol.\t{2:,.2f}\nLength\t{3:,.2f}\nMax. Cut Depth\t{0:.2f}\nAvg. Cut Depth\t{1:.2f}'.format(
            maxCut, avgCut, totVol, length)
        self.updateOutputText(outText)

        #            for layer in self.layers:
        #                utils.addSlLayer(self.iface,self.dbase,layer)

        self.iface.messageBar().pushMessage(
            "Drainge Channel Builder",
            'Channel elevation DEM, channel depth of cut DEM, and channel grid points located at {}.  Please delete when finished'
            .format(self.dirName),
            duration=30)

        # set channel dem qml by coping dem layer style to channel dem qml
        self.rLayer.saveNamedStyle(
            os.path.join(self.dirName,
                         demChannelPath.split('.tif')[0] + '.qml'))

        # set depth qml w/ function
        xmlString = utils.depthQMLwriter(maxCut)
        demCutDepthQML = open(demCutDepth.split('.tif')[0] + '.qml', 'w')
        demCutDepthQML.write(xmlString)
        demCutDepthQML.close()

        if self.checkBoxLoadLayers.checkState():
            for fileName in [demChannelPath, demCutDepth]:
                fileInfo = QFileInfo(fileName)
                baseName = fileInfo.baseName()
                layer = QgsRasterLayer(fileName, baseName)
                if not layer.isValid():
                    print "Layer failed to load!"
                QgsMapLayerRegistry.instance().addMapLayer(layer)

        self.progressBar.setMaximum(100)
        self.cbCL.setEnabled(True)
        self.cbDEM.setEnabled(True)
        self.spinRes.setEnabled(True)
        self.spinWidth.setEnabled(True)
        self.spinElevStart.setEnabled(True)
        self.spinElevEnd.setEnabled(True)
        self.spinLeftSideSlope.setEnabled(True)
        self.spinRightSideSlope.setEnabled(True)
        self.spinBankWidth.setEnabled(True)
        self.browseBtn.setEnabled(True)
        self.btn1Dsave.setEnabled(True)
        self.btnClose.setEnabled(True)
        self.btnOk.setEnabled(True)

        self.writeOut1Dresults()
        fileName = 'Channel2DresultsSummary_{}.txt'.format(self.vLayer.name())
        outText = 'DEM Layer:\t{0}\nChannel Centerline:\t{1}\nProjection (Proj4 format):\t{14}\n2D Grid Calc Res.:\t{2}\nChannel Bottom Width:\t{3}\nChannel Start Elevation:\t{4}\nChannel End Elevation:\t{5}\nChannel Slope:\t{13:.06f}\nLeft Side Slope:\t{6}\nRight Side Slope:\t{7}\n2D Maximum Bank Width:\t{8}\n\nLength:\t{9:,.2f}\n2D Max. Cut Depth:\t{10:,.2f}\n2D Avg. Cut Depth:\t{11:,.2f}\n2D Tot. Vol:\t{12:,.2f}\n\nNote:\tAll units of length correspond to layer units, all units of area and volume are a combination of layer units and raster elevation units\n\n'.format(
            self.cbDEM.currentText(), self.cbCL.currentText(),
            self.spinRes.value(), self.spinWidth.value(),
            self.spinElevStart.value(), self.spinElevEnd.value(),
            self.spinLeftSideSlope.value(), self.spinRightSideSlope.value(),
            self.spinBankWidth.value(), self.totLength, maxCut, avgCut, totVol,
            self.channelSlope,
            self.rLayer.crs().toProj4())
        outFile = open(fileName, 'w')
        outFile.write(outText)
        outFile.close()
        self.checkBoxLoadLayers.setCheckState(False)
        self.iface.mapCanvas().refresh()

    def accept(self):
        print 'accepted'

        args = [
            self.rLayer, self.vLayer,
            self.spinWidth.value(),
            self.spinRes.value(),
            self.spinElevStart.value(),
            self.spinElevEnd.value(),
            self.spinLeftSideSlope.value(),
            self.spinRightSideSlope.value(),
            self.spinBankWidth.value(),
            self.outputDir.text()
        ]
        self.thread = QThread()
        # create a new worker instance
        self.worker = DrainageChannelThread.DrainageChannelBuilder(args)

        # create a new worker instance
        self.worker.moveToThread(self.thread)
        self.worker.updateProgressText.connect(self.updateProgressText)

        self.worker.workerFinished.connect(self.workerFinished)
        self.worker.error.connect(self.workerError)

        self.btnClose.setEnabled(False)
        self.cbCL.setEnabled(False)
        self.cbDEM.setEnabled(False)
        self.spinRes.setEnabled(False)
        self.spinWidth.setEnabled(False)
        self.spinElevStart.setEnabled(False)
        self.spinElevEnd.setEnabled(False)
        self.spinLeftSideSlope.setEnabled(False)
        self.spinRightSideSlope.setEnabled(False)
        self.spinBankWidth.setEnabled(False)
        self.browseBtn.setEnabled(False)
        self.btn1Dsave.setEnabled(False)
        self.btnOk.setEnabled(False)
        self.tabWidgetOutput.setCurrentWidget(self.tabOutputSummary)

        #self.buttonBox.rejected.disconnect(self.reject)

        self.progressBar.setMaximum(0)
        self.thread.started.connect(self.worker.run)
        self.thread.start()

    def reject(self):
        print 'rejected'
        QtGui.QDialog.reject(self)
class MatplotlibExample(QtGui.QMainWindow):
    """HOW TO EMBED MATPLOTLIB WITH PYSIDE"""

    here = os.path.abspath(os.path.join(
        os.path.dirname(__file__)))  # to be overloaded
    media = os.path.abspath(os.path.join(here, "media"))

    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)

        self.x = None
        self.y = None
        self.last_idx = None

        # matplotlib stuff
        self.dpi = 200
        self.figure = None
        self.canvas = None
        self.axes = None
        self.mpl_toolbar = None

        # PySide stuff
        self.main_frame = None
        self.file_menu = None
        self.help_menu = None
        self.textbox = None
        self.draw_button = None
        self.grid_ck = None
        self.slider = None

        # create ui
        self.setWindowTitle('PySide with matplotlib')
        self.center()
        self.create_menu()
        self.create_main_frame()
        self.on_draw()

    def create_menu(self):
        """Menu creation"""
        # file menu
        self.file_menu = self.menuBar().addMenu("&File")
        load_file_action = self.create_action("&Save plot",
                                              shortcut="Ctrl+S",
                                              slot=self.save_plot,
                                              tip="Save the plot")
        self.file_menu.addAction(load_file_action)
        quit_action = self.create_action("&Quit",
                                         slot=self.close,
                                         shortcut="Ctrl+Q",
                                         tip="Close the app")
        self.file_menu.addAction(quit_action)
        # help menu
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About",
                                          shortcut='F1',
                                          slot=self.on_about,
                                          tip='About this app')
        self.help_menu.addAction(about_action)

    def create_action(self,
                      text,
                      slot=None,
                      shortcut=None,
                      icon=None,
                      tip=None,
                      checkable=False,
                      signal="triggered()"):
        """Helper function to create an action"""
        action = QtGui.QAction(text, self)
        if icon is not None:
            action.setIcon(
                QtGui.QIcon(os.path.join(self.media, "%s.png" % icon)))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def create_main_frame(self):
        self.main_frame = QtGui.QWidget()

        # Create Matplotlib figure and canvas
        self.figure = Figure((6.0, 4.0), dpi=self.dpi)  # inches, dots-per-inch
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setParent(self.main_frame)
        self.canvas.setFocusPolicy(
            QtCore.Qt.ClickFocus)  # key for press events!!!
        self.canvas.setFocus()
        # we use add_subplot (so that the subplot configuration tool in the navigation toolbar works)
        self.axes = self.figure.add_subplot(111)
        # Bind events
        self.canvas.mpl_connect('pick_event', self.on_pick)
        self.canvas.mpl_connect('button_press_event', self.on_mouse_press)
        self.canvas.mpl_connect('key_press_event', self.on_key_press)
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

        # other GUI controls
        self.textbox = QtGui.QLineEdit()
        self.textbox.setMinimumWidth(200)
        self.textbox.editingFinished.connect(self.on_draw)
        self.textbox.setText('1 3 2 6 3 2 4')
        self.draw_button = QtGui.QPushButton("&Draw")
        self.draw_button.clicked.connect(self.on_draw)
        # grid
        self.grid_ck = QtGui.QCheckBox("Show &Grid")
        self.grid_ck.setChecked(False)
        self.grid_ck.stateChanged.connect(self.on_draw)
        # slider
        slider_label = QtGui.QLabel('Plot width (%):')
        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
        self.slider.setRange(1, 100)
        self.slider.setValue(20)
        self.slider.setTracking(True)
        self.slider.setTickPosition(QtGui.QSlider.TicksBothSides)
        self.slider.valueChanged.connect(self.on_draw)

        # layouts
        hbox = QtGui.QHBoxLayout()
        for w in [
                self.textbox, self.draw_button, self.grid_ck, slider_label,
                self.slider
        ]:
            hbox.addWidget(w)
            hbox.setAlignment(w, QtCore.Qt.AlignVCenter)
        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def save_plot(self):
        flt = "PNG (*.png)|*.png"
        path = QtGui.QFileDialog.getSaveFileName(self, 'Save file', '', flt)
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)

    def on_about(self):
        msg = """PySide with matplotlib:
- navigation bar
- grid toggle
- interactivity ('Draw' button, slider, click on bar)
- plot saving
"""
        QtGui.QMessageBox.about(self, "About the demo", msg.strip())

    def on_pick(self, event):
        """Manage pick event"""
        if event.ind is None:
            return

        m_x = event.mouseevent.xdata
        m_y = event.mouseevent.ydata

        msg = "Click event:\n"
        msg += "ind: %s\n" % event.ind
        msg += "mouse.xdata/ydata: %s, %s\n" % (m_x, m_y)  # click location
        msg += "xydata:%s\n" % event.artist.get_xydata()

        print(msg)

        # in case of multiple selection
        distances = np.hypot(m_x - self.x[event.ind], m_y - self.y[event.ind])
        idx_min = distances.argmin()
        self.last_idx = event.ind[idx_min]

        self.update_plot()

    def on_key_press(self, event):
        """Manage press event"""
        print("pressed key: %s" % event.key)

    def on_mouse_press(self, event):
        """Manage press event"""
        print("pressed mouse: %s" % event.key)

    def on_draw(self):
        """Redraws the figure"""
        self.y = [int(d) for d in self.textbox.text().split()]
        self.x = range(len(self.y))

        # clear the axes and redraw
        self.axes.clear()
        self.axes.grid(self.grid_ck.isChecked())
        self.axes.plot(self.x,
                       self.y,
                       linewidth=self.slider.value() / 100.0,
                       alpha=0.5,
                       picker=3)
        self.canvas.draw()

    def update_plot(self):
        if self.last_idx is None:
            return
        print("update")

        self.on_draw()
        self.axes.text(self.x[self.last_idx],
                       self.y[self.last_idx],
                       'x=%1.3f\ny=%1.3f' %
                       (self.x[self.last_idx], self.y[self.last_idx]),
                       va='top')
        self.canvas.draw()
예제 #22
0
def plot_quiet_regions():
    # Plot the region that the noise was calculated from...
    # For TOT...
    TOT_bounds, VCD_bounds, THW_bounds = find_quiet_regions()

    # TOT/JKB2d/X16a gives:
    # mag = 32809.224658469, phs = -0.90421798501485484
    # VCD/JKB2g/DVD01a gives:
    # mag = 15720.217174332585, phs = -0.98350090576267946
    # THW/SJB2/DRP02a gives:
    # 26158.900202734963, phs = 1.6808311318828895

    TOT_fig = Figure((10, 8))
    TOT_canvas = FigureCanvas(TOT_fig)
    TOT_ax = TOT_fig.add_axes([0, 0, 1, 1])
    TOT_ax.axis('off')
    plot_radar(TOT_ax, 'TOT_LO', 3200, None, [135000, 234000])
    xlim = TOT_ax.get_xlim()
    ylim = TOT_ax.get_ylim()
    TOT_ax.vlines(TOT_bounds[0:2],
                  0,
                  3200,
                  colors='red',
                  linewidth=3,
                  linestyles='dashed')
    plot_bounding_box(TOT_ax, TOT_bounds, '', linewidth=4)
    TOT_ax.set_xlim(xlim)
    TOT_ax.set_ylim(ylim)
    TOT_canvas.print_figure('../FinalReport/figures/TOT_quiet_region.jpg')

    VCD_fig = Figure((10, 8))
    VCD_canvas = FigureCanvas(VCD_fig)
    VCD_ax = VCD_fig.add_axes([0, 0, 1, 1])
    VCD_ax.axis('off')
    plot_radar(VCD_ax, 'VCD_LO', 3200, None, [135000, 234000])
    xlim = VCD_ax.get_xlim()
    ylim = VCD_ax.get_ylim()
    VCD_ax.vlines(VCD_bounds[0:2],
                  0,
                  3200,
                  colors='red',
                  linewidth=3,
                  linestyles='dashed')
    plot_bounding_box(VCD_ax, VCD_bounds, '', linewidth=4)
    VCD_ax.set_xlim(xlim)
    VCD_ax.set_ylim(ylim)
    VCD_canvas.print_figure('../FinalReport/figures/VCD_quiet_region.jpg')

    THW_fig = Figure((10, 8))
    THW_canvas = FigureCanvas(THW_fig)
    THW_ax = THW_fig.add_axes([0, 0, 1, 1])
    THW_ax.axis('off')
    plot_radar(THW_ax, 'THW_LO', 3200, None, [135000, 234000])
    xlim = THW_ax.get_xlim()
    ylim = THW_ax.get_ylim()
    THW_ax.vlines(THW_bounds[0:2],
                  0,
                  3200,
                  colors='red',
                  linewidth=3,
                  linestyles='dashed')
    plot_bounding_box(THW_ax, THW_bounds, '', linewidth=4)
    THW_ax.set_xlim(xlim)
    THW_ax.set_ylim(ylim)
    THW_canvas.print_figure('../FinalReport/figures/THW_quiet_region.jpg')
예제 #23
0
class AppForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('Templar_2')
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        self.dacStatus = 'off'
        self.dramStatus = 'off'
        self.tapStatus = 'off'
        self.socketStatus = 'off'
        self.ch_all = []
        self.attens = numpy.array([1. for i in range(256)])
        #self.freqRes = 1953.125
        #self.freqRes = 7812.5
        self.sampleRate = 550e6
        N_lut_entries = 2**16
        self.freqRes = self.sampleRate/N_lut_entries

        #self.iq_centers = numpy.array([0.+0j]*256)
        
    def openClient(self):
        self.status_text.setText('connecting...')
        self.roach = corr.katcp_wrapper.FpgaClient(self.textbox_roachIP.text(),7147)
        time.sleep(2)
        self.status_text.setText('connecting...done')
        self.button_openClient.setDisabled(True)

    def programRFswitches(self, regStr = '10110'):
        #    5 bit word: LO_int/ext, RF_loop, LO_source(doubler), BB_loop, Ck_int/ext
        #regStr = self.textbox_rfSwReg.text()
        print int(regStr[0]), int(regStr[1]), int(regStr[2]),int(regStr[3]), int(regStr[4])

        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 1)
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[0])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[0])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[0])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[1])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[1])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[1])<<2)+(0<<1)+(0<<0))                
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[2])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[2])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[2])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[3])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[3])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[3])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[4])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[4])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[4])<<2)+(0<<1)+(0<<0))   

        # Now clock out the data written to the reg.
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))   
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))                        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 0)
        
    def programAttenuators(self, atten_in_desired, atten_out_desired):
        #    There are eight settings for each attenuator:
        #    0db, -0.5, -1, -2, -4, -8, -16, and -31.5, which
        #    are listed in order in "attenuations."    
        #atten_in_desired = float(self.textbox_atten_in.text())
        atten_in = 63 - int(atten_in_desired*2)
        
        #atten_out_desired = float(self.textbox_atten_out.text())
        if atten_out_desired <= 31.5:
            atten_out0 = 63
            atten_out1 = 63 - int(atten_out_desired*2)
        else:
            atten_out0 = 63 - int((atten_out_desired-31.5)*2)
            atten_out1 = 0

        reg = numpy.binary_repr((atten_in<<12)+(atten_out0<<6)+(atten_out1<<0))
        b = '0'*(18-len(reg)) + reg
        print reg, len(reg)
        self.roach.write_int('regs', (0<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 1)
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[0])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[0])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[0])<<2)+(0<<1)+(0<<0))

        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[1])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[1])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[1])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[2])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[2])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[2])<<2)+(0<<1)+(0<<0))

        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[3])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[3])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[3])<<2)+(0<<1)+(0<<0))

        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[4])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[4])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[4])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[5])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[5])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[5])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[6])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[6])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[6])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[7])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[7])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[7])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[8])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[8])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[8])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[9])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[9])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[9])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[10])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[10])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[10])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[11])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[11])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[11])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[12])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[12])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[12])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[13])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[13])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[13])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[14])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[14])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[14])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[15])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[15])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[15])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[16])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[16])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[16])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[17])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[17])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[17])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 0)
        
    def programLO(self, freq=3.2e9, sweep_freq=0):
        f_pfd = 10e6
        if sweep_freq:
            f = freq
        else:
            f = float(self.textbox_loFreq.text())
        if f >= 4.4e9:
            f = f/2
            
        INT = int(f)/int(f_pfd)
        MOD = 2000
        FRAC = int(round(MOD*(f/f_pfd-INT)))
        if FRAC != 0:
            gcd = fractions.gcd(MOD,FRAC)
            if gcd != 1:
                MOD = MOD/gcd
                FRAC = int(FRAC/gcd)
        PHASE = 1
        R = 1
        power = 3
        aux_power = 3
        MUX = 3
        LOCK_DETECT = 1
        reg5 = (LOCK_DETECT<<22) + (1<<2) + (1<<0)
        reg4 = (1<<23) + (1<<18) + (1<<16) + (1<<8) + (aux_power<<6) + (1<<5) + (power<<3) + (1<<2)
        reg3 = (1<<10) + (1<<7) + (1<<5) + (1<<4) + (1<<1) + (1<<0)
        reg2 = (MUX<<26) + (R<<14) + (1<<11) + (1<<10) + (1<<9) + (1<<7) + (1<<6) + (1<<1)
        reg1 = (1<<27) + (PHASE<<15) + (MOD<<3) + (1<<0)
        reg0 = (INT<<15) + (FRAC<<3)
        
        regs = [reg5, reg4, reg3, reg2, reg1, reg0]
        
        for r in regs:
            self.roach.write_int('SER_DI', r)
            self.roach.write_int('LO_SLE', 1)
            self.roach.write_int('start', 1)
            self.roach.write_int('start', 0)
            self.roach.write_int('LO_SLE', 0)

    def define_LUTs(self):
        self.iq_centers = numpy.array([0.+0j]*256)
        self.define_DAC_LUT()
        self.define_DDS_LUT()
        self.write_LUTs()
        #self.loadLUTs()
        
        print "luts defined and loaded."
        
    def freqCombLUT(self, echo, freq, sampleRate, resolution, amplitude=[1.]*256, phase=[0.]*256, random_phase = 'yes'):
        offset = int(self.textbox_offset.text())
        amp_full_scale = 2**15-1
        N_freqs = len(freq)
        size = int(sampleRate/resolution)
        I, Q = numpy.array([0.]*size), numpy.array([0.]*size)
        single_I, single_Q = numpy.array([0.]*size), numpy.array([0.]*size)
        
        numpy.random.seed(1000)
        for n in range(N_freqs):
            if random_phase == 'yes':
                phase[n] = numpy.random.uniform(0, 2*numpy.pi)
                
            #start_x = phase[n]+2*numpy.pi*freq[n]*offset/sampleRate
            #end_x = phase[n]+2*numpy.pi*freq[n]*(size+offset)/sampleRate
            #x = numpy.linspace(start_x, end_x, size)
            
            #start_y = phase[n]
            #end_y = phase[n]+2*numpy.pi*freq[n]*(size)/sampleRate
            #y = numpy.linspace(start_y, end_y, size)
            
            x = [2*numpy.pi*freq[n]*(t+offset)/sampleRate+phase[n] for t in range(size)]
            y = [2*numpy.pi*freq[n]*t/sampleRate+phase[n] for t in range(size)]
            
            single_I = amplitude[n]*numpy.cos(x)
            single_Q = amplitude[n]*numpy.sin(y)

            I = I + single_I
            Q = Q + single_Q
        
        a = numpy.array([abs(I).max(), abs(Q).max()])
        I = numpy.array([int(i*amp_full_scale/a.max()) for i in I])
        Q = numpy.array([int(q*amp_full_scale/a.max()) for q in Q])
        if echo == 'yes':
            print 'scale factor: ', a.max()
            self.scale_factor = a.max()
            print 'Set atten_out to: ', 20*numpy.log10(self.previous_scale_factor/self.scale_factor) + self.minimumAttenuation
        return I, Q
        
    def define_DAC_LUT(self):
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        resFreqs = numpy.array(freqs)
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + self.sampleRate
        self.freqs_dac = [round((f-f_base)/self.freqRes)*self.freqRes for f in freqs]
        atten_min = self.attens.min()
        print numpy.array(self.freqs_dac) + f_base
        print "minimum attenuation: ", self.minimumAttenuation
        amplitudes = [10**(+(atten_min-a)/20.) for a in self.attens]
        self.I_dac, self.Q_dac = self.freqCombLUT('yes', self.freqs_dac, self.sampleRate, self.freqRes, amplitudes)
        print 'done defining DAC freqs.'
        
    def define_DDS_LUT(self, phase = [0.]*256):
        fft_len=2**9
        ch_shift = int(self.textbox_dds_shift.text())
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + self.sampleRate#512e6

        freqs_dds = [0 for j in range(256)]
        for n in range(len(freqs)):
            freqs_dds[n] = round((freqs[n]-f_base)/self.freqRes)*self.freqRes

        freq_residuals = self.select_bins(freqs_dds)

        L = int(self.sampleRate/self.freqRes)
        self.I_dds, self.Q_dds = [0.]*L, [0.]*L
        for m in range(256):
            #I, Q = self.freqCombLUT('no', [freq_residuals[m]], 2e6, self.freqRes, [1.], [phase[m]], 'no')
            I, Q = self.freqCombLUT('no', [freq_residuals[m]], self.sampleRate/fft_len*2, self.freqRes, [1.], [phase[m]], 'no')
            for j in range(len(I)/2):
                self.I_dds[j*512+2*((m+ch_shift)%256)] = I[2*j]
                self.I_dds[j*512+2*((m+ch_shift)%256)+1] = I[2*j+1]
                self.Q_dds[j*512+2*((m+ch_shift)%256)] = Q[2*j]
                self.Q_dds[j*512+2*((m+ch_shift)%256)+1] = Q[2*j+1]

        print "done defing dds freqs. "

    def select_bins(self, readout_freqs):
        fft_len = 2**9
        bins = ''
        i = 0
        residuals = []
        for f in readout_freqs:
            fft_bin = int(round(f*fft_len/self.sampleRate))
            fft_freq = fft_bin*self.sampleRate/fft_len
            freq_residual = round((f - fft_freq)/self.freqRes)*self.freqRes
            residuals.append(freq_residual)
            bins = bins + struct.pack('>l', fft_bin)
            self.roach.write_int('bins', fft_bin)
            self.roach.write_int('load_bins', (i<<1) + (1<<0))
            self.roach.write_int('load_bins', (i<<1) + (0<<0))
            i = i + 1
        return residuals
    
    def write_LUTs(self):
        if self.dacStatus == 'off':
            self.roach.write_int('startDAC', 0)
        else:
            self.toggleDAC()
            
        binaryData = ''
        print len(self.I_dac)
        self.axes0.clear()
        self.axes0.plot(range(len(self.I_dac)),self.I_dac,'r-')
        self.axes0.plot(range(len(self.I_dds)),self.I_dds,'b-')
        self.canvas.draw()
        for n in range(len(self.I_dac)/2):
            i_dac_0 = struct.pack('>h', self.I_dac[2*n])
            i_dac_1 = struct.pack('>h', self.I_dac[2*n+1])
            i_dds_0 = struct.pack('>h', self.I_dds[2*n])
            i_dds_1 = struct.pack('>h', self.I_dds[2*n+1])
            q_dac_0 = struct.pack('>h', self.Q_dac[2*n])
            q_dac_1 = struct.pack('>h', self.Q_dac[2*n+1])
            q_dds_0 = struct.pack('>h', self.Q_dds[2*n])
            q_dds_1 = struct.pack('>h', self.Q_dds[2*n+1])
            binaryData = binaryData + q_dds_1 + q_dds_0 + q_dac_1 + q_dac_0 + i_dds_1 + i_dds_0 + i_dac_1 + i_dac_0
        self.roach.write('dram_memory', binaryData)
        
        # Write LUTs to file.
        saveDir = str(self.textbox_saveDir.text())
        f = open(saveDir + 'luts.dat', 'w')
        f.write(binaryData)
        f.close()

    def loadIQcenters(self):
        saveDir = str(self.textbox_saveDir.text())
        centers_for_file = [[0., 0.]]*256
        for ch in range(256):
            I_c = int(self.iq_centers[ch].real/2**3)
            Q_c = int(self.iq_centers[ch].imag/2**3)

            center = (I_c<<16) + (Q_c<<0)
            self.roach.write_int('conv_phase_centers', center)
            self.roach.write_int('conv_phase_load_centers', (ch<<1)+(1<<0))
            self.roach.write_int('conv_phase_load_centers', 0)
        
            centers_for_file[ch] = [self.iq_centers[ch].real, self.iq_centers[ch].imag]
            
        numpy.savetxt(saveDir+'centers.dat', centers_for_file)

    def findIQcenters(self, I, Q):
        I_0 = (I.max()+I.min())/2.
        Q_0 = (Q.max()+Q.min())/2.
                
        return complex(I_0, Q_0)
  
    def rotateLoops(self):
        print "Calculating loop rotations..."
        dac_freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        N_freqs = len(dac_freqs)
        phase = [0.]*256
        
        self.roach.write_int('startAccumulator', 0)
        self.roach.write_int('avgIQ_ctrl', 1)
        self.roach.write_int('avgIQ_ctrl', 0)
        self.roach.write_int('startAccumulator', 1)
        time.sleep(0.001)
        data = self.roach.read('avgIQ_bram', 4*2*256)
        for n in range(N_freqs):
            I = struct.unpack('>l', data[4*n:4*n+4])[0]-self.iq_centers[n].real
            Q = struct.unpack('>l', data[4*(n+256):4*(n+256)+4])[0]-self.iq_centers[n].imag
            
            phase[n] = numpy.arctan2(Q, I)

        self.define_DDS_LUT(phase)
        self.write_LUTs()
        """ Since the DAC is toggled OFF in write_LUTs, it needs to be turned back on with the following.
            """
        self.toggleDAC()
        self.sweepLO()
            
    def sweepLO(self):
        atten_in = float(self.textbox_atten_in.text())
        saveDir = str(self.textbox_saveDir.text())
        savefile = saveDir + 'ps_' + time.strftime("%Y%m%d-%H%M%S",time.localtime()) + '.h5'
        dac_freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        self.N_freqs = len(dac_freqs)
        f_base = float(self.textbox_loFreq.text())
        
        if f_base >= 4.4e9:
            self.programRFswitches('10010')
            print 'LO doubled.'
        else:
            self.programRFswitches('10110')
            print 'LO normal operation.'
        loSpan = float(self.textbox_loSpan.text())
        df = 1e4
        steps = int(loSpan/df)
        print "LO steps: ", steps
        lo_freqs = [f_base+i*df-0.5*steps*df for i in range(steps)]
        
        atten_start = int(self.textbox_powerSweepStart.text())
        atten_stop = int(self.textbox_powerSweepStop.text())
        if atten_start <= atten_stop:
            attens = [i for i in range(atten_start, atten_stop+1)]
        else:
            attens = [i for i in range(atten_start, atten_stop-1, -1)]

        for a in attens:	
            print a
            self.programAttenuators(atten_in, a)
            time.sleep(0.5)
            f_span = []
            l = 0
            self.f_span = [[0]*steps]*self.N_freqs
            for f in dac_freqs:
                f_span = f_span + [f-0.5*steps*df+n*df for n in range(steps)]
                self.f_span[l] = [f-0.5*steps*df+n*df for n in range(steps)]
                l = l + 1
            I = numpy.zeros(self.N_freqs*steps, dtype='float32')
            Q = numpy.zeros(self.N_freqs*steps, dtype='float32')
            I_std = numpy.zeros(self.N_freqs*steps, dtype='float32')
            Q_std = numpy.zeros(self.N_freqs*steps, dtype='float32')

            self.I, self.Q = numpy.array([[0.]*steps]*self.N_freqs),numpy.array([[0.]*steps]*self.N_freqs)
            for i in range(steps):
                #print i
                self.programLO(lo_freqs[i],1)
                self.roach.write_int('startAccumulator', 0)
                self.roach.write_int('avgIQ_ctrl', 1)
                self.roach.write_int('avgIQ_ctrl', 0)
                self.roach.write_int('startAccumulator', 1)
                time.sleep(0.001)
                data = self.roach.read('avgIQ_bram', 4*2*256)
                for j in range(self.N_freqs):
                    I[j*steps+i] = struct.unpack('>l', data[4*j:4*j+4])[0]
                    Q[j*steps+i] = struct.unpack('>l', data[4*(j+256):4*(j+256)+4])[0]
                    I_std[j*steps+i] = 0
                    Q_std[j*steps+i] = 0
                    self.I[j, i] = I[j*steps+i]
                    self.Q[j, i] = Q[j*steps+i]
            self.programLO(f_base,1)
            
            # Find IQ centers.
            self.I_on_res, self.Q_on_res = [0.]*self.N_freqs, [0.]*self.N_freqs
            self.roach.write_int('startAccumulator', 0)
            self.roach.write_int('avgIQ_ctrl', 1)
            self.roach.write_int('avgIQ_ctrl', 0)
            self.roach.write_int('startAccumulator', 1)
            time.sleep(0.001)
            data = self.roach.read('avgIQ_bram', 4*2*256)
            for j in range(self.N_freqs):
                self.I_on_res[j] = struct.unpack('>l', data[4*j:4*j+4])[0]
                self.Q_on_res[j] = struct.unpack('>l', data[4*(j+256):4*(j+256)+4])[0]
                self.iq_centers[j] = self.findIQcenters(I[j*steps:j*steps+steps],Q[j*steps:j*steps+steps])
            
            
            N = steps*self.N_freqs
	
            for n in range(self.N_freqs):
                w = iqsweep.IQsweep()
                w.f0 = dac_freqs[n]/1e9
                w.span = steps*df/1e6
                w.fsteps = steps
                #w.atten1 = a
                w.atten1 = a + self.attens[n]
                #w.atten1 = atten
                # w.atten2 is actually the "scale factor" used in the DAC LUT
                # generation.
                w.atten2 = 0
                w.scale = self.scale_factor
                w.PreadoutdB = -w.atten1 - 20*numpy.log10(self.scale_factor)
                w.Tstart = 0.100
                w.Tend = 0.100
                w.I0 = 0.0
                w.Q0 = 0.0
                w.resnum = n
                w.freq =  numpy.array(f_span[n*steps:(n+1)*steps], dtype='float32')/1e9
                w.I = I[n*steps:(n+1)*steps]
                w.Q = Q[n*steps:(n+1)*steps]
                w.Isd = I_std[n*steps:(n+1)*steps]
                w.Qsd = Q_std[n*steps:(n+1)*steps]
                w.time = time.time()
                w.savenoise = 0
                w.Save(savefile,'r0', 'a')
            
            
        self.axes0.clear()
        self.axes1.clear()
        self.axes0.semilogy(f_span, (I**2 + Q**2)**.5, '.-')
        self.axes1.plot(I, Q, '.-', self.iq_centers.real[0:self.N_freqs], self.iq_centers.imag[0:self.N_freqs], '.', self.I_on_res, self.Q_on_res, '.')
        self.canvas.draw()

    def toggleDAC(self):
        if self.dacStatus == 'off':
            print "Starting DAC...",
            self.roach.write_int('startDAC', 1)
            time.sleep(1)
            while self.roach.read_int('DRAM_LUT_rd_valid') != 0:
                self.roach.write_int('startDAC', 0)
                time.sleep(0.25)
                self.roach.write_int('startDAC', 1)
                time.sleep(1)
                print ".",
            f_base = float(self.textbox_loFreq.text())
            self.programLO(f_base,1)
            self.button_startDAC.setText('Stop DAC')
            self.dacStatus = 'on'
            self.status_text.setText('DAC turned on. ')       
            print "done"
        else:
            print "Stopping DAC..."
            self.roach.write_int('startDAC', 0)
            self.button_startDAC.setText('Start DAC')
            self.dacStatus = 'off'
            print "done"
            self.status_text.setText('DAC turned off. ')       
   
    def loadFreqsAttens(self):
        f_base = float(self.textbox_loFreq.text())
        freqFile =str(self.textbox_freqFile.text())
        x = numpy.loadtxt(freqFile) 
        x_string = ''
        
        self.previous_scale_factor = x[0,0] 
        N_freqs = len(x[1:,0])
        for l in x[1:,0]:
            x_string = x_string + str(l*1e9) + '\n'
            
        self.iq_centers = numpy.array([0.+0j]*256)
        for n in range(N_freqs):
            #for n in range(256):
            self.iq_centers[n] = complex(x[n+1,1], x[n+1,2])
            
        self.attens = x[1:,3]
        self.minimumAttenuation = numpy.array(x[1:,3]).min()
        self.textedit_DACfreqs.setText(x_string)
        
    def loadLUTs(self):
        self.scale_factor = 1.
        self.iq_centers = numpy.array([0.+0j]*256)
        
        # Loads the DAC and DDS LUTs from file.  As well as the IQ loop centers.
        if self.dacStatus == 'off':
            self.roach.write_int('startDAC', 0)
        else:
            self.toggleDAC()

        saveDir = str(self.textbox_saveDir.text())          
        f = open(saveDir+'luts.dat', 'r')
        binaryData = f.read()

        self.roach.write('dram_memory', binaryData)

        x = numpy.loadtxt(saveDir+'centers.dat')
        N_freqs = len(x[:,0])
        for n in range(N_freqs):
            self.iq_centers[n] = complex(x[n,0], x[n,1])
        
        #    Select and write bins for first stage of channelizer.
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + self.sampleRate#512e6

        freqs_dds = [0 for j in range(256)]
        for n in range(len(freqs)):
            freqs_dds[n] = round((freqs[n]-f_base)/self.freqRes)*self.freqRes

        freq_residuals = self.select_bins(freqs_dds)
        
        print 'LUTs and IQ centers loaded from file.'

    def channelIncUp(self):
        ch = int(self.textbox_channel.text())
        ch = ch + 1
        ch = ch%self.N_freqs
        self.textbox_channel.setText(str(ch))
        self.axes0.clear()
        self.axes1.clear()
        self.axes0.semilogy(self.f_span[ch], (self.I[ch]**2 + self.Q[ch]**2)**.5, '.-')
        self.axes1.plot(self.I[ch], self.Q[ch], '.-', self.iq_centers.real[ch], self.iq_centers.imag[ch], '.', self.I_on_res[ch], self.Q_on_res[ch], '.')
        self.canvas.draw()
        
    def channelIncDown(self):
        ch = int(self.textbox_channel.text())
        ch = ch - 1
        ch = ch%self.N_freqs
        self.textbox_channel.setText(str(ch))
        self.axes0.clear()
        self.axes1.clear()
        self.axes0.semilogy(self.f_span[ch], (self.I[ch]**2 + self.Q[ch]**2)**.5, '.-')
        self.axes1.plot(self.I[ch], self.Q[ch], '.-', self.iq_centers.real[ch], self.iq_centers.imag[ch], '.', self.I_on_res[ch], self.Q_on_res[ch], '.')
        self.canvas.draw()

    def changeCenter(self, event):
        I = event.xdata
        Q = event.ydata
        ch = int(self.textbox_channel.text())
        print ch
        self.iq_centers.real[ch] = I
        self.iq_centers.imag[ch] = Q
        self.axes1.plot(I, Q, '.')
        self.canvas.draw()
 
    def create_main_frame(self):
        self.main_frame = QWidget()
        
        # Create the mpl Figure and FigCanvas objects. 
        self.dpi = 100
        self.fig = Figure((9.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        self.axes0 = self.fig.add_subplot(121)
        self.axes1 = self.fig.add_subplot(122)
        
        cid=self.canvas.mpl_connect('button_press_event', self.changeCenter)
        
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Roach board's IP address
        self.textbox_roachIP = QLineEdit('10.0.0.10')
        self.textbox_roachIP.setMaximumWidth(200)
        label_roachIP = QLabel('Roach IP Address:')

        # Start connection to roach.
        self.button_openClient = QPushButton("(1)Open Client")
        self.button_openClient.setMaximumWidth(100)
        self.connect(self.button_openClient, SIGNAL('clicked()'), self.openClient)
        
        # LO frequency.
        self.textbox_loFreq = QLineEdit('3.5e9')
        self.textbox_loFreq.setMaximumWidth(100)
        label_loFreq = QLabel('LO frequency:')

        # Sweep span
        self.textbox_loSpan = QLineEdit('0.5e6')
        self.textbox_loSpan.setMaximumWidth(50)
        label_loSpan = QLabel('LO Span:')
        
        # Frequency span shift
        # A span shift of 0.75 shifts 75% of sweep span to the lower portion of the range.
        self.textbox_spanShift = QLineEdit('0.5')
        self.textbox_spanShift.setMaximumWidth(50)
        label_spanShift = QLabel('Span shift')
        
        # DAC Frequencies.
        self.textedit_DACfreqs = QTextEdit()
        self.textedit_DACfreqs.setMaximumWidth(170)
        self.textedit_DACfreqs.setMaximumHeight(100)
        label_DACfreqs = QLabel('DAC Freqs:')

        # Input attenuation.
        self.textbox_atten_in = QLineEdit('0')
        self.textbox_atten_in.setMaximumWidth(50)
        label_atten_in = QLabel('Input atten.:')

        # offset in lut
        self.textbox_offset = QLineEdit('0')
        self.textbox_offset.setMaximumWidth(50)
        label_offset = QLabel('DAC sync. lag:')
		
        # offset in lut
        self.textbox_dds_shift = QLineEdit('144')
        self.textbox_dds_shift.setMaximumWidth(50)
        label_dds_shift = QLabel('DDS sync. lag:')

        # Power sweep range. 
        self.textbox_powerSweepStart = QLineEdit('16')
        self.textbox_powerSweepStart.setMaximumWidth(50)
        label_powerSweepStart = QLabel('Start atten.:')
        self.textbox_powerSweepStop = QLineEdit('16')
        self.textbox_powerSweepStop.setMaximumWidth(50)
        label_powerSweepStop = QLabel('Stop atten:')

        # Save directory
        self.textbox_saveDir = QLineEdit('/home/sean/data/20120713/freqs.txt')
        self.textbox_saveDir.setMaximumWidth(250)
        label_saveDir = QLabel('Save directory:')
        label_saveDir.setMaximumWidth(150)
    
        # File with frequencies/attens
        self.textbox_freqFile = QLineEdit('/home/sean/data/20120713/freqs.txt')
        self.textbox_freqFile.setMaximumWidth(200)

        # Load freqs and attens from file.
        self.button_loadFreqsAttens = QPushButton("(2)Load freqs/attens")
        self.button_loadFreqsAttens.setMaximumWidth(200)
        self.connect(self.button_loadFreqsAttens, SIGNAL('clicked()'), self.loadFreqsAttens)
        
        # Rotate IQ loops.
        self.button_rotateLoops = QPushButton("(6)Rot. Loops")
        self.button_rotateLoops.setMaximumWidth(150)
        self.connect(self.button_rotateLoops, SIGNAL('clicked()'), self.rotateLoops)        

        # Translate IQ loops.
        self.button_translateLoops = QPushButton("(7)Trans. Loops")
        self.button_translateLoops.setMaximumWidth(150)
        self.connect(self.button_translateLoops, SIGNAL('clicked()'), self.loadIQcenters)
        
        # DAC start button.
        self.button_startDAC = QPushButton("(4)Start DAC")
        self.button_startDAC.setMaximumWidth(200)
        self.connect(self.button_startDAC, SIGNAL('clicked()'), self.toggleDAC)
        
        # define DAC/DDS frequencies and load LUTs. 
        self.button_define_LUTs= QPushButton("(3)Define LUTs")
        self.button_define_LUTs.setMaximumWidth(200)
        self.connect(self.button_define_LUTs, SIGNAL('clicked()'), self.define_LUTs)

        # Sweep LO
        self.button_sweepLO = QPushButton("(5)Sweep LO")
        self.button_sweepLO.setMaximumWidth(340)
        self.connect(self.button_sweepLO, SIGNAL('clicked()'), self.sweepLO)    
          
        # Channel increment up 1.
        self.button_channelIncUp = QPushButton("+")
        self.button_channelIncUp.setMaximumWidth(50)
        self.connect(self.button_channelIncUp, SIGNAL('clicked()'), self.channelIncUp)
        
        # Channel increment down 1.
        self.button_channelIncDown = QPushButton("-")
        self.button_channelIncDown.setMaximumWidth(50)
        self.connect(self.button_channelIncDown, SIGNAL('clicked()'), self.channelIncDown)
        
        # Channel to measure
        self.textbox_channel = QLineEdit('0')
        self.textbox_channel.setMaximumWidth(40)
        label_channel = QLabel('Ch:')
        label_channel.setMaximumWidth(50)
        
        # Add widgets to window.
        gbox0 = QVBoxLayout()
        hbox00 = QHBoxLayout()
        hbox00.addWidget(self.textbox_roachIP)
        hbox00.addWidget(self.button_openClient)
        gbox0.addLayout(hbox00)
        hbox01 = QHBoxLayout()
        hbox01.addWidget(self.textbox_freqFile)
        hbox01.addWidget(self.button_loadFreqsAttens)
        gbox0.addLayout(hbox01)
        hbox02 = QHBoxLayout()
        hbox02.addWidget(label_saveDir)
        hbox02.addWidget(self.textbox_saveDir)
        gbox0.addLayout(hbox02)
        hbox03 = QHBoxLayout()
        hbox03.addWidget(label_loFreq)
        hbox03.addWidget(self.textbox_loFreq)
        gbox0.addLayout(hbox03)

        gbox1 = QVBoxLayout()
        gbox1.addWidget(label_DACfreqs)
        gbox1.addWidget(self.textedit_DACfreqs)
        hbox10 = QHBoxLayout()
        hbox10.addWidget(label_offset)
        hbox10.addWidget(self.textbox_offset)
        hbox11 = QHBoxLayout()
        hbox11.addWidget(label_dds_shift)
        hbox11.addWidget(self.textbox_dds_shift)
        gbox1.addLayout(hbox10)
        gbox1.addLayout(hbox11)
        gbox1.addWidget(self.button_define_LUTs)
        gbox1.addWidget(self.button_startDAC)

        gbox2 = QVBoxLayout()
        hbox20 = QHBoxLayout()
        hbox20.addWidget(label_atten_in)
        hbox20.addWidget(self.textbox_atten_in)
        hbox20.addWidget(label_powerSweepStart)
        hbox20.addWidget(self.textbox_powerSweepStart)
        hbox20.addWidget(label_powerSweepStop)
        hbox20.addWidget(self.textbox_powerSweepStop)
        gbox2.addLayout(hbox20)
        hbox21 = QHBoxLayout()
        hbox21.addWidget(label_loSpan)
        hbox21.addWidget(self.textbox_loSpan)
        hbox21.addWidget(self.button_sweepLO)
        gbox2.addLayout(hbox21)
        hbox22 = QHBoxLayout()
        hbox22.addWidget(label_channel)
        hbox22.addWidget(self.textbox_channel)
        hbox22.addWidget(self.button_channelIncDown)
        hbox22.addWidget(self.button_channelIncUp)
        gbox2.addLayout(hbox22)
        hbox23 = QHBoxLayout()
        hbox23.addWidget(self.button_rotateLoops)
        hbox23.addWidget(self.button_translateLoops)
        gbox2.addLayout(hbox23)
 
        hbox = QHBoxLayout()
        hbox.addLayout(gbox0)
        hbox.addLayout(gbox1)     
        hbox.addLayout(gbox2)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
  
    def create_status_bar(self):
        self.status_text = QLabel("Awaiting orders.")
        self.statusBar().addWidget(self.status_text, 1)
        
    def create_menu(self):        
        self.file_menu = self.menuBar().addMenu("&File")
        
        load_file_action = self.create_action("&Save plot",
            shortcut="Ctrl+S", slot=self.save_plot, 
            tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close, 
            shortcut="Ctrl+Q", tip="Close the application")
        
        self.add_actions(self.file_menu, 
            (load_file_action, None, quit_action))
        
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About the demo')
        
        self.add_actions(self.help_menu, (about_action,))

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        
        path = unicode(QFileDialog.getSaveFileName(self, 
                        'Save file', '', 
                        file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def on_about(self):
        msg = """ Message to user goes here.
        """
        QMessageBox.about(self, "MKID-ROACH software demo", msg.strip())
예제 #24
0
def plot_LO_fft():
    # pik1_utils does all of this ...
    filename = WAIS + '/orig/xlob/TOT/JKB2d/X16a/RADnh3/bxds'

    trace_start, trace_end = 405450, 415450  # This is 8109 - 8309 in pik1 traces
    correction = pik1_utils.find_LO_params(filename, 2, 3437, trace_start,
                                           trace_end)
    print "LO correction: ", correction
    print "mag = %r, phs = %r" % (np.abs(correction), np.angle(correction))

    # Plot the fft of the full traces
    input_sweeps = pik1_utils.load_raw_nh3_subset_gen(
        filename, 2, np.arange(trace_start, trace_end), 3437, 3200, 200)
    input_stacked = pik1_utils.coherent_stack_gen(input_sweeps, 50)
    radar_data = np.array([trace for trace in input_stacked])
    radar_fft = np.fft.fft(radar_data, n=3200)
    fftfreq3200 = np.fft.fftfreq(3200, 1 / 50.)
    fig2 = Figure((10, 8))
    canvas2 = FigureCanvas(fig2)
    ax2 = fig2.add_axes([0, 0, 1, 1])
    ax2.imshow(np.abs(radar_fft), cmap='gray', aspect='auto')
    canvas2.print_figure('../FinalReport/figures/data_fft.jpg')

    # Plot the fft of the bottom portion only
    input_sweeps = pik1_utils.load_raw_nh3_subset_gen(
        filename, 2, np.arange(trace_start, trace_end), 3437, 3437, 200)
    input_stacked = pik1_utils.coherent_stack_gen(input_sweeps, 50)
    noise_data = np.array([trace[-800:] for trace in input_stacked])
    noise_fft = np.fft.fft(noise_data, n=800)
    fftfreq800 = np.fft.fftfreq(800, 1 / 50.)
    fig3 = Figure((10, 8))
    canvas3 = FigureCanvas(fig3)
    ax3 = fig3.add_axes([0, 0, 1, 1])
    ax3.imshow(np.abs(noise_fft), cmap='gray', aspect='auto')
    canvas3.print_figure('../FinalReport/figures/noise_fft.jpg')

    # TODO: Maybe just to nice clean line plots showing full transect and bottom?
    fig4 = Figure((15, 5))
    canvas4 = FigureCanvas(fig4)
    ax4 = fig4.add_axes([0.01, 0.2, 0.98, 0.8])
    abs_noise_fft = np.sum(np.abs(noise_fft), axis=0)
    # cancel out constant term.
    abs_noise_fft[0] = 0
    plot_noise_fft = abs_noise_fft / np.max(abs_noise_fft)
    ax4.plot(fftfreq800[1:400], plot_noise_fft[1:400], color='black')
    ax4.plot(fftfreq800[401:800], plot_noise_fft[401:800], color='black')
    # Cancel out the two biggest peaks.
    abs_noise_fft[160] = 0
    abs_noise_fft[640] = 0
    plot_noise_fft2 = abs_noise_fft / np.max(abs_noise_fft)
    ax4.plot(fftfreq800[1:400], plot_noise_fft2[1:400], color='darkgrey')
    ax4.plot(fftfreq800[401:800], plot_noise_fft2[401:800], color='darkgrey')
    abs_radar_fft = np.sum(np.abs(radar_fft), axis=0)
    plot_radar_fft = abs_radar_fft / np.max(abs_radar_fft)
    # Plot in two chunks to avoid the awkward line across the figure.
    ax4.plot(fftfreq3200[1:1600], plot_radar_fft[1:1600], color='red')
    ax4.plot(fftfreq3200[1601:3200], plot_radar_fft[1601:3200], color='red')

    ax.set_ylim([0, 1.05])
    ax4.set_xlim([-25, 25])
    ax4.tick_params(which='both',
                    bottom=True,
                    top=False,
                    left=False,
                    right=False,
                    labelbottom=True,
                    labeltop=False,
                    labelleft=False,
                    labelright=False,
                    labelsize=18)
    for side in ['top', 'left', 'right']:
        ax4.spines[side].set_visible(False)
    ax4.set_xlabel('Frequency (MHz)', fontsize=24)

    canvas4.print_figure('../FinalReport/figures/LO_fft.jpg')
예제 #25
0
class AppForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('Channelizer 2')
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        self.dacStatus = 'off'
        self.dramStatus = 'off'
        self.tapStatus = 'off'
        self.socketStatus = 'off'
        self.ch_all = []
        self.attens = numpy.array([1. for i in range(256)])
        self.sampleRate = 550e6
        N_lut_entries = 2**16
        self.freqRes = self.sampleRate/N_lut_entries
        #self.freqRes = 7812.5
        self.zeroChannels = [0]*256
        self.thresholds, self.medians = numpy.array([0.]*256), numpy.array([0.]*256)
        
    def openClient(self):
        self.roach = corr.katcp_wrapper.FpgaClient(self.textbox_roachIP.text(),7147)
        time.sleep(2)
        self.status_text.setText('connection established')
        self.button_openClient.setDisabled(True)

    def loadFIRcoeffs(self):
        N_freqs = len(map(float, unicode(self.textedit_DACfreqs.toPlainText()).split()))
        taps = 26
        
        for ch in range(N_freqs):
            # If the dark count rate is very high, the channel will be zeroed.
            if self.zeroChannels[ch]:
                lpf = numpy.array([0.]*taps)*(2**11-1)
            else:
                print ch
                #lpf = numpy.array([1.]+[0]*(taps-1))*(2**11-1)
		#    26 tap, 25 us matched fir
                lpf = numpy.array([0.0875788844768 , 0.0840583257978 , 0.0810527406206 , 0.0779008825067 , 0.075106964962 , 0.0721712998256 , 0.0689723729398 , 0.066450095496 , 0.0638302570705 , 0.0613005685486 , 0.0589247737004 , 0.0565981917436 , 0.0544878914297 , 0.0524710948658 , 0.0503447054014 , 0.0483170854189 , 0.0463121066637 , 0.044504238059 , 0.0428469827102 , 0.0410615366471 , 0.0395570640218 , 0.0380071830756 , 0.0364836787854 , 0.034960959124 , 0.033456372241 , 0.0321854467182])*(2**11-1)
                #lpf = lpf[::-1]
                #    26 tap, lpf, 250 kHz,
                #lpf = numpy.array([-0 , 0.000166959420533 , 0.00173811663844 , 0.00420937801998 , 0.00333739357391 , -0.0056305703275 , -0.0212738104942 , -0.0318529375832 , -0.0193635986879 , 0.0285916612022 , 0.106763943766 , 0.18981814328 , 0.243495321192 , 0.243495321192 , 0.18981814328 , 0.106763943766 , 0.0285916612022 , -0.0193635986879 , -0.0318529375832 , -0.0212738104942 , -0.0056305703275 , 0.00333739357391 , 0.00420937801998 , 0.00173811663844 , 0.000166959420533 , -0])*(2**11-1)
                #    26 tap, lpf, 125 kHz.
                #lpf = numpy.array([0 , -0.000431898216436 , -0.00157886921107 , -0.00255492263971 , -0.00171727439076 , 0.00289724121972 , 0.0129123447233 , 0.0289345497995 , 0.0500906370566 , 0.0739622085341 , 0.0969821586979 , 0.115211955161 , 0.125291869266 , 0.125291869266 , 0.115211955161 , 0.0969821586979 , 0.0739622085341 , 0.0500906370566 , 0.0289345497995 , 0.0129123447233 , 0.00289724121972 , -0.00171727439076 , -0.00255492263971 , -0.00157886921107 , -0.000431898216436 , -0])*(2**11-1)
                #    Generic 40 tap matched filter for 25 us lifetime pulse
                #lpf = numpy.array([0.153725595011 , 0.141052390733 , 0.129753816201 , 0.119528429291 , 0.110045314901 , 0.101336838027 , 0.0933265803805 , 0.0862038188673 , 0.0794067694409 , 0.0729543134914 , 0.0674101836798 , 0.0618283869464 , 0.0567253144676 , 0.0519730940444 , 0.047978953698 , 0.043791412767 , 0.0404560656757 , 0.0372466775252 , 0.0345000956808 , 0.0319243455811 , 0.0293425115323 , 0.0268372778298 , 0.0245216835234 , 0.0226817116475 , 0.0208024488535 , 0.0189575043357 , 0.0174290665862 , 0.0158791788119 , 0.0144611054123 , 0.0132599563305 , 0.0121083419203 , 0.0109003580368 , 0.0100328742978 , 0.00939328253743 , 0.00842247241585 , 0.00789304712484 , 0.00725494259117 , 0.00664528407122 , 0.00606688645845 , 0.00552041438208])*(2**11-1)                
                #lpf = lpf[::-1]
            for n in range(taps/2):
                coeff0 = int(lpf[2*n])
                coeff1 = int(lpf[2*n+1])
                coeff0 = numpy.binary_repr(int(lpf[2*n]), 12)
                coeff1 = numpy.binary_repr(int(lpf[2*n+1]), 12)
                coeffs = int(coeff1+coeff0, 2)
                coeffs_bin = struct.pack('>l', coeffs)
                register_name = 'FIR_b' + str(2*n) + 'b' + str(2*n+1)
                self.roach.write(register_name, coeffs_bin)
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (1<<0))
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (0<<0))
        
        # Inactive channels will also be zeroed.
        lpf = numpy.array([0.]*taps)
        for ch in range(N_freqs, 256):
            for n in range(taps/2):
                #coeffs = struct.pack('>h', lpf[2*n]) + struct.pack('>h', lpf[2*n+1])
                coeffs = struct.pack('>h', lpf[2*n+1]) + struct.pack('>h', lpf[2*n])
                register_name = 'FIR_b' + str(2*n) + 'b' + str(2*n+1)
                self.roach.write(register_name, coeffs)
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (1<<0))
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (0<<0))
                
        print 'done loading fir.' 
     
    def find_nearest(self, array, value):
        idx=(numpy.abs(array-value)).argmin()
        return idx

    def loadThresholds(self):
        """    Takes two time streams and concatenates together for a longer sample.
                median is used instead of mean.
                """
        x = raw_input('Is the lamp off? ')
        Nsigma = float(self.textbox_Nsigma.text())
        N_freqs = len(map(float, unicode(self.textedit_DACfreqs.toPlainText()).split()))
        self.thresholds, self.medians = numpy.array([0.]*N_freqs), numpy.array([0.]*N_freqs)
        steps = int(self.textbox_timeLengths.text())
        L = 2**10
        for ch in range(N_freqs):
            bin_data_phase = ''
            for n in range(steps):
                self.roach.write_int('ch_we', ch)
                self.roach.write_int('startSnap', 0)
                self.roach.write_int('snapPhase_ctrl', 1)
                self.roach.write_int('snapPhase_ctrl', 0)
                self.roach.write_int('startSnap', 1)
                time.sleep(0.001)
                bin_data_phase = bin_data_phase + self.roach.read('snapPhase_bram', 4*L)    
            
            phase = []
            for m in range(steps*L):
                phase.append(struct.unpack('>h', bin_data_phase[m*4+2:m*4+4])[0])
                phase.append(struct.unpack('>h', bin_data_phase[m*4+0:m*4+2])[0])
            phase = numpy.array(phase)
            #phase_avg = numpy.median(phase)
            #sigma = phase.std()

            n,bins= numpy.histogram(phase,bins=100)
            n = numpy.array(n,dtype='float32')/numpy.sum(n)
            tot = numpy.zeros(len(bins))
            for i in xrange(len(bins)):
                tot[i] = numpy.sum(n[:i])
            bins1 = .5*(bins[1:]+bins[:-1])
            med = bins[self.find_nearest(tot,0.5)]
            thresh = bins[self.find_nearest(tot,0.05)]
            threshold = int(med-Nsigma*abs(med-thresh))
            
            scale_to_angle = 360./2**16*4/numpy.pi
            #threshold = int((phase_avg - Nsigma*sigma))
            # -25736 = -180 degrees
            if threshold < -25736:
                threshold = -25736
            self.thresholds[ch] = scale_to_angle*threshold
            self.medians[ch] = scale_to_angle*med

            self.roach.write_int('capture_threshold', threshold)
            self.roach.write_int('capture_load_thresh', (ch<<1)+(1<<0))
            self.roach.write_int('capture_load_thresh', (ch<<1)+(0<<0))
            print "channel: ", ch, "median: ", scale_to_angle*med, "threshold: ", scale_to_angle*threshold
            #print "channel: ", ch, "avg: ", scale_to_angle*phase_avg, "sigma: ", scale_to_angle*sigma, "threshold: ", scale_to_angle*threshold
        
    def snapshot(self):        
        ch_we = int(self.textbox_channel.text())
        self.roach.write_int('ch_we', ch_we)
        #print self.roach.read_int('ch_we')
        
        steps = int(self.textbox_timeLengths.text())
        L = 2**10
        bin_data_phase = ''
        for n in range(steps):
            self.roach.write_int('startSnap', 0)
            self.roach.write_int('snapPhase_ctrl', 1)
            self.roach.write_int('snapPhase_ctrl', 0)
            self.roach.write_int('startSnap', 1)
            time.sleep(0.001)
            bin_data_phase = bin_data_phase + self.roach.read('snapPhase_bram', 4*L)    
            
        phase = []
        for m in range(steps*L):
            phase.append(struct.unpack('>h', bin_data_phase[m*4+2:m*4+4])[0])
            phase.append(struct.unpack('>h', bin_data_phase[m*4+0:m*4+2])[0])
        phase = numpy.array(phase)*360./2**16*4/numpy.pi

        self.axes1.clear()
        self.axes1.plot(phase, '.-', [self.thresholds[ch_we]]*2*L*steps, 'r.', [self.medians[ch_we]]*2*L*steps, 'g.')
        self.canvas.draw()

    def readPulses(self):
        scale_to_degrees = 360./2**12*4/numpy.pi
        channel_count = [0]*256
        p1 = [[]]*256
        timestamp = [[]]*256
        for i in range(256):
            p1[i] = [0]
            timestamp[i] = [0]
            
        seconds = int(self.textbox_seconds.text())
        self.roach.write_int('startBuffer', 1)
        for n in range(seconds):
            addr0 = self.roach.read_int('pulses_addr')
            time.sleep(1.0)
            addr1 = self.roach.read_int('pulses_addr')
            bin_data_0 = self.roach.read('pulses_bram0', 4*2**14)
            bin_data_1 = self.roach.read('pulses_bram1', 4*2**14)

            if addr1 >= addr0:
                total_counts = addr1-addr0
                for n in range(addr0, addr1):
                    raw_data_1 = struct.unpack('>L', bin_data_1[n*4:n*4+4])[0]
                    raw_data_0 = struct.unpack('>L', bin_data_0[n*4:n*4+4])[0]
                    ch = raw_data_1/2**24
                    channel_count[ch] = channel_count[ch] + 1
                    p1[ch].append((raw_data_1%2**12 - 2**11)*scale_to_degrees)
                    timestamp[ch].append(raw_data_0%2**20)
            else:
                total_counts = addr1+2**14-addr0
                for n in range(addr0, 2**14):
                    raw_data_1 = struct.unpack('>L', bin_data_1[n*4:n*4+4])[0]
                    raw_data_0 = struct.unpack('>L', bin_data_0[n*4:n*4+4])[0]
                    ch = raw_data_1/2**24
                    channel_count[ch] = channel_count[ch] + 1
                    p1[ch].append((raw_data_1%2**12 - 2**11)*scale_to_degrees)
                    timestamp[ch].append(raw_data_0%2**20)
                for n in range(0, addr1):
                    raw_data_1 = struct.unpack('>L', bin_data_1[n*4:n*4+4])[0]
                    raw_data_0 = struct.unpack('>L', bin_data_0[n*4:n*4+4])[0]
                    ch = raw_data_1/2**24
                    channel_count[ch] = channel_count[ch] + 1
                    p1[ch].append((raw_data_1%2**12 - 2**11)*scale_to_degrees)
                    timestamp[ch].append(raw_data_0%2**20)
            print total_counts
        self.roach.write_int('startBuffer', 0)

        print channel_count
        ch = int(self.textbox_channel.text())
        numpy.savetxt('/home/sean/data/restest/test.dat', p1[ch])
        
        # With lamp off, run "readPulses."  If count rate is above 50, it's anamolous 
        # and it's FIR should be set to 0.
        #for n in range(256):
         #   if channel_count[n] > 100:
          #      self.zeroChannels[n] = 1   
        
        #x = numpy.arange(-270, 0, 3)
        #y = numpy.histogram(data, 90)
        self.axes0.clear()
        self.axes0.plot(timestamp[ch], '.')
        self.canvas.draw()

    def channelInc(self):
        ch_we = int(self.textbox_channel.text())
        ch_we = ch_we + 1
        self.textbox_channel.setText(str(ch_we))
        
    def toggleDAC(self):
        if self.dacStatus == 'off':
            print "Starting LUT...",
            self.roach.write_int('startDAC', 1)
            time.sleep(1)
            while self.roach.read_int('DRAM_LUT_rd_valid') != 0:
                self.roach.write_int('startDAC', 0)
                time.sleep(0.25)
                self.roach.write_int('startDAC', 1)
                time.sleep(1)
                print ".",
            print "done."
            #self.button_startDAC.setText('Stop DAC')
            self.dacStatus = 'on'
	    self.status_text.setText('DAC turned on. ')       
        else:
            self.roach.write_int('startDAC', 0)
            #self.button_startDAC.setText('Start DAC')
            self.dacStatus = 'off'
	    self.status_text.setText('DAC turned off. ')       

    def loadIQcenters(self):
        for ch in range(256):
            I_c = int(self.iq_centers[ch].real/2**3)
            Q_c = int(self.iq_centers[ch].imag/2**3)

            center = (I_c<<16) + (Q_c<<0)
            self.roach.write_int('conv_phase_centers', center)
            self.roach.write_int('conv_phase_load_centers', (ch<<1)+(1<<0))
            self.roach.write_int('conv_phase_load_centers', 0)

    def select_bins(self, readout_freqs):
        fft_len = 2**9
        bins = ''
        i = 0
        residuals = []
        for f in readout_freqs:
            fft_bin = int(round(f*fft_len/self.sampleRate))
            fft_freq = fft_bin*self.sampleRate/fft_len
            freq_residual = round((f - fft_freq)/self.freqRes)*self.freqRes
            residuals.append(freq_residual)
            bins = bins + struct.pack('>l', fft_bin)
            self.roach.write_int('bins', fft_bin)
            self.roach.write_int('load_bins', (i<<1) + (1<<0))
            self.roach.write_int('load_bins', (i<<1) + (0<<0))
            i = i + 1
        self.status_text.setText('done writing LUTs. ')
        return residuals
  
    def loadLUTs(self):
        self.scale_factor = 1.
        self.iq_centers = numpy.array([0.+0j]*256)
        
        # Loads the DAC and DDS LUTs from file.  As well as the IQ loop centers.
        if self.dacStatus == 'off':
            self.roach.write_int('startDAC', 0)
        else:
            self.toggleDAC()

        saveDir = str(self.textbox_lutDir.text())
        #saveDir = str(os.environ['PWD'] + '/'+ self.textbox_lutDir.text())            
        f = open(saveDir+'luts.dat', 'r')
        binaryData = f.read()

        self.roach.write('dram_memory', binaryData)

        x = numpy.loadtxt(saveDir+'centers.dat')
        N_freqs = len(x[:,0])
        for n in range(N_freqs):
            self.iq_centers[n] = complex(x[n,0], x[n,1])
        
        #    Select and write bins for first stage of channelizer.
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + 512e6
        freqs_dds = [0 for j in range(256)]
        for n in range(len(freqs)):
            freqs_dds[n] = round((freqs[n]-f_base)/self.freqRes)*self.freqRes
        freq_residuals = self.select_bins(freqs_dds)
        
        print 'LUTs and IQ centers loaded from file.'
        self.loadIQcenters()
        self.toggleDAC()
   
    def importFreqs(self):
        freqFile =str(self.textbox_freqFile.text())
        x = numpy.loadtxt(freqFile) 
        x_string = ''
        
        self.previous_scale_factor = x[0,0] 
        N_freqs = len(x[1:,0])
        for l in x[1:,0]:
            x_string = x_string + str(l*1e9) + '\n'
            
        self.iq_centers = numpy.array([0.+0j]*256)
        for n in range(N_freqs):
            #for n in range(256):
            self.iq_centers[n] = complex(x[n+1,1], x[n+1,2])
            
        self.attens = x[1:,3]
        self.textedit_DACfreqs.setText(x_string)

        self.zeroChannels = [0]*256
        
    def importFIRcoeffs(self):
        coeffsFile =str(self.textbox_coeffsFile.text())
        x = numpy.loadtxt(coeffsFile)
  
    def file_dialog(self):
        print 'add dialog box here'
        #self.newdatadir = QFileDialog.getExistingDirectory(self, str("Choose SaveDirectory"), "",QFileDialog.ShowDirsOnly)
         #if len(self.newdatadir) > 0:
          #   self.datadir = self.newdatadir
           #  print self.datadir
             #self.ui.data_directory_lineEdit.setText(self.datadir) #put new path name in line edit
            # self.button_saveDir.setText(str(self.datadir))
             
    def create_main_frame(self):
        self.main_frame = QWidget()
        
        # Create the mpl Figure and FigCanvas objects. 
        self.dpi = 100
        self.fig = Figure((9.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        self.axes0 = self.fig.add_subplot(121)
        self.axes1 = self.fig.add_subplot(122)
        
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Roach board's IP address
        self.textbox_roachIP = QLineEdit('10.0.0.10')
        self.textbox_roachIP.setMaximumWidth(200)
        label_roachIP = QLabel('Roach IP Address:')

        # Start connection to roach.
        self.button_openClient = QPushButton("(1)Open Client")
        self.button_openClient.setMaximumWidth(100)
        self.connect(self.button_openClient, SIGNAL('clicked()'), self.openClient)
        
        # DAC Frequencies.
        self.textedit_DACfreqs = QTextEdit()
        self.textedit_DACfreqs.setMaximumWidth(170)
        self.textedit_DACfreqs.setMaximumHeight(100)
        label_DACfreqs = QLabel('DAC Freqs:')
    
        # File with frequencies/attens
        self.textbox_freqFile = QLineEdit('/home/sean/data/20120812adr/freqs0.txt')
        self.textbox_freqFile.setMaximumWidth(200)

        # Import freqs from file.
        self.button_importFreqs = QPushButton("(2)Load freqs")
        self.button_importFreqs.setMaximumWidth(200)
        self.connect(self.button_importFreqs, SIGNAL('clicked()'), self.importFreqs)   

        # File with FIR coefficients
        self.textbox_coeffsFile = QLineEdit('/home/sean/data/20110803/r0/')
        self.textbox_coeffsFile.setMaximumWidth(200)

        # Import FIR coefficients from file.
        self.button_importFIRcoeffs = QPushButton("Import FIR coeffs.")
        self.button_importFIRcoeffs.setMaximumWidth(200)
        self.connect(self.button_importFIRcoeffs, SIGNAL('clicked()'), self.importFIRcoeffs) 

        # Channel increment by 1.
        self.button_channelInc = QPushButton("Channel++")
        self.button_channelInc.setMaximumWidth(100)
        self.connect(self.button_channelInc, SIGNAL('clicked()'), self.channelInc)

        # Load FIR coefficients.
        self.button_loadFIRcoeffs = QPushButton("(3)load FIR")
        self.button_loadFIRcoeffs.setMaximumWidth(170)
        self.connect(self.button_loadFIRcoeffs, SIGNAL('clicked()'), self.loadFIRcoeffs)

        # Load thresholds.
        self.button_loadThresholds = QPushButton("(4)load thresholds")
        self.button_loadThresholds.setMaximumWidth(170)
        self.connect(self.button_loadThresholds, SIGNAL('clicked()'), self.loadThresholds)
        
        # Channel to measure
        self.textbox_channel = QLineEdit('0')
        self.textbox_channel.setMaximumWidth(50)

        # threshold N*sigma
        self.textbox_Nsigma = QLineEdit('5.0')
        self.textbox_Nsigma.setMaximumWidth(50)
        label_Nsigma = QLabel('sigma       ')
        
        # Time snapshot of a single channel
        self.button_snapshot = QPushButton("snapshot")
        self.button_snapshot.setMaximumWidth(170)
        self.connect(self.button_snapshot, SIGNAL('clicked()'), self.snapshot)            
        
        # Read pulses
        self.button_readPulses = QPushButton("Read pulses")
        self.button_readPulses.setMaximumWidth(170)
        self.connect(self.button_readPulses, SIGNAL('clicked()'), self.readPulses)   
        
        # Seconds for "read pulses."
        self.textbox_seconds = QLineEdit('10')
        self.textbox_seconds.setMaximumWidth(50)
        
        # lengths of 1 ms for defining thresholds.
        self.textbox_timeLengths = QLineEdit('10')
        self.textbox_timeLengths.setMaximumWidth(50)
        label_timeLengths = QLabel('mSeconds       ')
        
        # Add widgets to window.
        gbox0 = QVBoxLayout()
        hbox00 = QHBoxLayout()
        hbox00.addWidget(self.textbox_roachIP)
        hbox00.addWidget(self.button_openClient)
        gbox0.addLayout(hbox00)
        hbox01 = QHBoxLayout()
        hbox01.addWidget(self.textbox_freqFile)
        hbox01.addWidget(self.button_importFreqs)
        gbox0.addLayout(hbox01)
        hbox02 = QHBoxLayout()
        hbox02.addWidget(self.textbox_coeffsFile)
        hbox02.addWidget(self.button_importFIRcoeffs)
        hbox02.addWidget(self.button_loadFIRcoeffs)
        gbox0.addLayout(hbox02)
        hbox03 = QHBoxLayout()
        hbox03.addWidget(self.textbox_timeLengths)
        hbox03.addWidget(label_timeLengths)
        hbox03.addWidget(self.textbox_Nsigma)
        hbox03.addWidget(label_Nsigma)
        hbox03.addWidget(self.button_loadThresholds)
        gbox0.addLayout(hbox03)
        
        gbox1 = QVBoxLayout()
        gbox1.addWidget(label_DACfreqs)
        gbox1.addWidget(self.textedit_DACfreqs)

        gbox2 = QVBoxLayout()
        hbox20 = QHBoxLayout()
        hbox20.addWidget(self.textbox_channel)
        hbox20.addWidget(self.button_channelInc)
        gbox2.addLayout(hbox20)
        gbox2.addWidget(self.button_snapshot)
        hbox21 = QHBoxLayout()
        hbox21.addWidget(self.textbox_seconds)
        hbox21.addWidget(self.button_readPulses)
        gbox2.addLayout(hbox21)


        hbox = QHBoxLayout()
        hbox.addLayout(gbox0)
        hbox.addLayout(gbox1)     
        hbox.addLayout(gbox2)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
  
    def create_status_bar(self):
        self.status_text = QLabel("Awaiting orders.")
        self.statusBar().addWidget(self.status_text, 1)
        
    def create_menu(self):        
        self.file_menu = self.menuBar().addMenu("&File")
        
        load_file_action = self.create_action("&Save plot",shortcut="Ctrl+S", slot=self.save_plot, tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close, shortcut="Ctrl+Q", tip="Close the application")
        
        self.add_actions(self.file_menu, (load_file_action, None, quit_action))
        
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the demo')
        
        self.add_actions(self.help_menu, (about_action,))

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '',file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def on_about(self):
        msg = """ Message to user goes here.
        """
        QMessageBox.about(self, "MKID-ROACH software demo", msg.strip())
예제 #26
0
def plot_trace():
    # Trace 3900 in pik1 looks pretty nice.
    trace_idx = 3900
    num_in_samples = 3437
    num_out_samples = 3200

    raw_y = 2  #(where to plot the raw data ...)
    raw_filename = WAIS + '/orig/xlob/TOT/JKB2d/X16a/RADnh3/bxds'
    # For plotting, I tried raw dB of trace ... I don't like it as much
    # If I try it again, gotta be careful - abs(elem) can cause overflow errors if we don't cast to float first!
    sweep_gen = pik1_utils.load_raw_nh3_subset_gen(raw_filename, 2,
                                                   [50 * trace_idx],
                                                   num_in_samples,
                                                   num_out_samples, 0)
    raw_trace = [elem for elem in sweep_gen][0]
    raw_min = np.min(raw_trace)
    raw_range = 1.0 * np.max(raw_trace) - np.min(raw_trace)
    norm_raw_trace_ch2 = [
        raw_y + (1.0 * elem - raw_min) / raw_range for elem in raw_trace
    ]

    sweep_gen = pik1_utils.load_raw_nh3_subset_gen(raw_filename, 1,
                                                   [50 * trace_idx],
                                                   num_in_samples,
                                                   num_out_samples, 0)
    raw_trace = [elem for elem in sweep_gen][0]
    raw_min = np.min(raw_trace)
    raw_range = 1.0 * np.max(raw_trace) - np.min(raw_trace)
    norm_raw_trace_ch1 = [
        raw_y + 1 + (1.0 * elem - raw_min) / raw_range for elem in raw_trace
    ]

    pik1_filename = 'TOT_LO'
    num_traces = pik1_utils.get_num_traces(pik1_filename, num_in_samples)
    pik1_data = np.memmap(pik1_filename,
                          '>i4',
                          mode='r',
                          shape=(num_traces, num_out_samples))
    processed_trace = pik1_data[trace_idx, :]
    trace_min = np.min(processed_trace)
    trace_range = np.max(processed_trace) - np.min(processed_trace)
    norm_processed_trace = [
        1.0 * (elem - trace_min) / trace_range for elem in processed_trace
    ]

    fig = Figure((30, 15))
    canvas = FigureCanvas(fig)
    ax = fig.add_axes([0, 0, 1, 1])
    ax.minorticks_off()
    ax.tick_params(which='both',
                   bottom=False,
                   top=False,
                   left=False,
                   right=False,
                   labelbottom=False,
                   labeltop=False,
                   labelleft=False,
                   labelright=False)
    for side in ['bottom', 'top', 'left', 'right']:
        ax.spines[side].set_visible(False)

    ax.set_xlim([0, 3200])
    ylim = [0, raw_y + 2]
    ax.set_ylim(ylim)

    bar_y1 = 1.15
    bar_y2 = 1.25
    bar_y3 = 1.35
    text_y1 = 1.0
    text_y2 = 1.3
    text_y3 = 1.4

    fontsize = 50
    xshift = 66  # WTF. Why do I have to offset the raw pulse to make it line up with the dechirped?

    # reference chirp 50-100
    ax.plot([50, 100], [1.65, 1.65], color='red', linewidth=15)
    ax.text(25,
            1.7,
            'chirp',
            fontsize=50,
            color='red',
            horizontalalignment='left',
            verticalalignment='bottom')

    # "main bang"
    ax.plot([100, 540], [1.35, 1.35], '--', color='red', linewidth=15)
    ax.plot([100, 400], [1.35, 1.35], color='red', linewidth=15)
    ax.text(250,
            1.4,
            'main bang',
            fontsize=50,
            color='red',
            horizontalalignment='center',
            verticalalignment='bottom')

    # hardware blanking from 1-134 (in theory ... I don't trust this from the resulting plots
    ax.plot([xshift + 0, xshift + 134], [1.15, 1.15],
            color='red',
            linewidth=15)
    ax.text(xshift,
            0.9,
            'HW blanking',
            fontsize=50,
            color='red',
            horizontalalignment='left',
            verticalalignment='bottom')

    # software blanking from 1-200
    ax.plot([0, 200], [0.85, 0.85], color='red', linewidth=15)
    ax.text(25,
            0.6,
            'SW blanking',
            fontsize=50,
            color='red',
            horizontalalignment='left',
            verticalalignment='bottom')

    # Surface at 555
    ax.plot([555, 555], ylim, color='lightgray', linewidth=15)
    ax.text(575,
            1.3,
            'ice surface',
            fontsize=50,
            color='black',
            horizontalalignment='left',
            verticalalignment='bottom')

    # surface multiple at 950
    ax.plot([950, 950], ylim, color='lightgray', linewidth=15)
    ax.text(970,
            0.9,
            'surface \nmultiple',
            fontsize=50,
            color='black',
            horizontalalignment='left',
            verticalalignment='bottom')

    # Crevasses at 1262
    ax.plot([1262, 1262], ylim, color='lightgray', linewidth=15)
    ax.text(1282,
            1.7,
            'crevasse',
            fontsize=50,
            color='black',
            horizontalalignment='left',
            verticalalignment='bottom')

    # water at 1378
    ax.plot([1378, 1378], ylim, color='lightgray', linewidth=15)
    ax.text(1398,
            0.85,
            'water',
            fontsize=50,
            color='black',
            horizontalalignment='left',
            verticalalignment='bottom')

    # off-nadir energy at 1400 - 1850
    ax.plot([1400, 2100], [bar_y2, bar_y2], '--', color='red', linewidth=15)
    ax.plot([1500, 1850], [bar_y2, bar_y2], color='red', linewidth=15)
    ax.text(1750,
            text_y2,
            'off-nadir energy',
            fontsize=50,
            color='red',
            horizontalalignment='center',
            verticalalignment='bottom')

    # bed multiple at 2204
    ax.plot([2204, 2204], ylim, color='lightgray', linewidth=15)
    ax.text(2224,
            0.5,
            'bed multiple',
            fontsize=50,
            color='black',
            horizontalalignment='left',
            verticalalignment='bottom')

    # noise at 2400 - 3200 (Can I call this receiver noise?)
    ax.plot([2250, 3200], [bar_y2, bar_y2], '--', color='red', linewidth=15)
    ax.plot([2400, 3200], [bar_y2, bar_y2], color='red', linewidth=15)
    ax.text(2725,
            text_y2,
            'receiver noise',
            fontsize=50,
            color='red',
            horizontalalignment='center',
            verticalalignment='bottom')

    # Ideas:
    # * have 3 different y values, for things that apply to one, the other, or both?
    # * shade the background to make it clearer what's going on?
    #   or at least draw light vertical grey bars for the point events?
    # * Be sure to show where this trace comes from on a transect ...

    # ax1 = fig.add_axes([0.0, 0.05, 0.5, 0.9])
    # ax1.set_ylim([3200, 0])
    # ax1.minorticks_off()
    # ax1.tick_params(which='both',
    #                 bottom=False, top=False, left=False, right=False,
    #                 labelbottom=False, labeltop=False, labelleft=False, labelright=False)

    # for side in ['bottom', 'top', 'left', 'right']:
    #     ax1.spines[side].set_visible(False)

    # ax2 = fig.add_axes([0.5, 0.05, 0.5, 0.9])
    # ax2.plot(processed_trace, range(len(processed_trace)), 'k', markersize=1)

    # ax2.set_ylim([3200, 0])
    # ax2.minorticks_on()
    # ax2.tick_params(which='both', direction='inout', labelsize=18,
    #                 bottom=False, top=False, left=True, right=False,
    #                 labelbottom=False, labeltop=False, labelleft=True, labelright=False)

    # for side in ['bottom', 'top', 'right']:
    #     ax2.spines[side].set_visible(False)

    ax.plot(range(len(norm_processed_trace)),
            norm_processed_trace,
            'k.',
            markersize=6)
    #ax.plot(range(len(norm_processed_trace)), norm_processed_trace, color='lightgrey', linewidth=1)
    ax.plot(np.arange(xshift, xshift + len(norm_raw_trace_ch2)),
            norm_raw_trace_ch2,
            'k.',
            markersize=6)
    ax.plot(np.arange(xshift, xshift + len(norm_raw_trace_ch1)),
            norm_raw_trace_ch1,
            'k.',
            markersize=6)

    canvas.print_figure('../FinalReport/figures/trace.jpg')
class CutePlot(QMainWindow):
    
    def __init__(self, parent=None):
        super(CutePlot, self).__init__(parent)
        
        # Default values for lower and upper bound
        self.LB_default = -10
        self.UB_default = 10
        # Create main plot area + menus + status bar
        self.create_main_frame()
        #self.textbox.setText()
        self.LB_UB_defaults()
        self.on_draw()
        self.statusBar()
        self.setWindowTitle('Graficador')
        self.create_menu()
        self.guardarImagen()

    def LB_UB_defaults(self):
        # Set default values for lower bound and upper bound
        self.lowerbound.setText(str(self.LB_default))
        self.upperbound.setText(str(self.UB_default))
        
    def create_main_frame(self):
        self.main_frame = QWidget()
        # 7x5 inches, 80 dots-per-inch
        self.dpi = 80
        self.fig = Figure((7, 5), dpi = self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        self.guardarImagen()
        self.is_data = False
        
        self.axes = self.fig.add_subplot(111)
        
        # axis_state keeps track of how many subplots are present
        # axis_state = 0: main plot only
        # axis_state = 1: horizontal split (quadrants 1 and 2)
        # axis_state = 2: vertical split (quadrants 1 and 4)
        # axis_state = 3: show all 4 subplots
        self.axis_state = 0
        
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # f(x) textbox
        self.title = QLabel('<font size=4><em>f</em> (<em>x </em>) =</font>')
        self.textbox = QLineEdit()
        self.textbox.setMinimumWidth(200)
        self.connect(self.textbox, SIGNAL('returnPressed()'), self.on_draw)
        
        # Lowerbound and upperbound textboxes
        self.LB_title = QLabel('<font size=4>Min:</font>')
        self.lowerbound = QLineEdit()
        self.lowerbound.setMaximumWidth(30)
        self.connect(self.lowerbound, SIGNAL('returnPressed()'), self.on_draw)
        
        self.UB_title = QLabel('<font size=4>Max:</font>')
        self.upperbound = QLineEdit()
        self.upperbound.setMaximumWidth(30)
        self.connect(self.upperbound, SIGNAL('returnPressed()'), self.on_draw)
        
        # Plot button
        self.draw_button = QPushButton("&Plot")
        self.connect(self.draw_button, SIGNAL('clicked()'), self.on_draw)

        # Hold checkbox
        self.hold_cb = QCheckBox("&Hold")
        self.hold_cb.setChecked(False)
        self.connect(self.hold_cb, SIGNAL('stateChanged(int)'), self.on_minor_change)
        self.hold_cb.setToolTip('Prevent new plots from replacing old ones')
        self.hold_cb.setStatusTip('Prevent new plots from replacing old ones')
        
        # Log-x and log-y checkboxes
        self.logx_cb = QCheckBox("Log-&x")
        self.logx_cb.setChecked(False)
        self.connect(self.logx_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        self.logx_cb.setToolTip('Change x-axis to logarithmic scale')
        self.logx_cb.setStatusTip('Change x-axis to logarithmic scale')
        
        self.logy_cb = QCheckBox("Log-&y")
        self.logy_cb.setChecked(False)
        self.connect(self.logy_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        self.logy_cb.setToolTip('Change y-axis to logarithmic scale')
        self.logy_cb.setStatusTip('Change y-axis to logarithmic scale')
        
        # Truncated-log checkbox
        self.trunc_cb = QCheckBox("Show &Negative")
        self.trunc_cb.setChecked(False)
        self.connect(self.trunc_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        self.trunc_cb.setToolTip('Plot negative values of log-transformed functions')
        self.trunc_cb.setStatusTip('Plot negative values of log-transformed functions')
        
        # Grid checkbox
        self.grid_cb = QCheckBox("&Grid")
        self.grid_cb.setChecked(False)
        self.connect(self.grid_cb, SIGNAL('stateChanged(int)'), self.on_minor_change)
        self.grid_cb.setToolTip('Show grid')
        self.grid_cb.setStatusTip('Show grid')
        
        # Grid layout
        grid = QGridLayout()
        grid.setSpacing(10)
        
        gridCol = 0
        for w in [self.title, self.textbox, self.LB_title, self.lowerbound, self.UB_title, 
                    self.upperbound, self.draw_button]:
            grid.addWidget(w, 0, gridCol)
            gridCol += 1
        
        grid2 = QGridLayout()
        grid2.setSpacing(10)
        gridCol = 0
        for w in [self.logx_cb, self.logy_cb, self.trunc_cb, self.hold_cb, self.grid_cb]:
            grid2.addWidget(w, 0, gridCol)
            gridCol += 1
        
        vbox = QVBoxLayout()
        vbox.addLayout(grid)
        vbox.addLayout(grid2)
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
                    
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
       
    
    def on_minor_change(self):
        self.on_draw(self.is_data)
       
        
    def on_draw(self, *args):
        # Get x-domain from user input
        self.LB_input = unicode(self.lowerbound.text())
        self.UB_input = unicode(self.upperbound.text())
        
        # Message box error if the domain inputs aren't int or float types
        # If float, round to the nearest 0.1
        round_to = 10
        try:
            self.LB_float = int(self.LB_input)*round_to
            self.UB_float = int(self.UB_input)*round_to
        except:
            self.LB_UB_defaults()
            QMessageBox.question(self, 'Error',
                '<center>Minimum and maximum values must be<br />\
                integer or floating-point numbers.</center>', QMessageBox.Ok)
        
        # Make sure UB > LB
        if self.UB_float <= self.LB_float:
            self.LB_UB_defaults()
            QMessageBox.question(self, 'Error',
                '<center>Maximum must be greater\
                than minimum value.</center>', QMessageBox.Ok)
        
        # If plotting a function, then get x and y values
        if len(args) == 0:
            self.is_data = False
        
            # Set x values (/round_to is to use range() with floating-point numbers)
            self.input_x = range(self.LB_float, self.UB_float + 1)
            self.input_x = [i/float(round_to) for i in self.input_x]
            
            # Calculate f(x) values for specified function
            fx = unicode(self.textbox.text())
            # If the f(x) field is empty, then default to y = 0 plot
            if fx == '':
                self.y = [0 for i in self.input_x]
            # Otherwise, evaluate the specified function and get ready to plot
            else:
                # Replace exp with numbers
                fx = fx.replace('exp', str(exp(1)) + '**')
                # Allow users to enter ^ for powers (replace ^ with **)
                fx = fx.replace('^', '**')
                # Try and evaluate; if there is an error, then shift slightly to the right
                try:
                    self.y = [eval(fx) for x in self.input_x]
                except:
                    fx = fx.replace('x', '(x + 10**(-6))')
                    self.y = [eval(fx) for x in self.input_x]        
            self.plot_symbol = '-'
        if self.is_data:
            self.plot_symbol = 'o'
        
        # If the hold box is checked, then new plots do not erase old ones
        new_state = self.quad_check()
        if self.axis_state == 0:
            self.axes.hold(self.hold_cb.isChecked())
        else:
            if self.hold_cb.isChecked():
                # If 'hold' is checked, see what quadrants will be shown
                # - if the quadrant state changes, remove subplots
                # - otherwise retain subplots
                if self.axis_state == 0 and new_state == 0:
                    self.axes.hold(self.hold_cb.isChecked())
                elif self.axis_state == 3 and new_state == 3:
                    self.axes_Q1.hold(self.hold_cb.isChecked())
                    self.axes_Q2.hold(self.hold_cb.isChecked())
                    self.axes_Q3.hold(self.hold_cb.isChecked())
                    self.axes_Q4.hold(self.hold_cb.isChecked())
                elif self.axis_state == 1 and new_state == 1:
                    self.axes_Q1.hold(self.hold_cb.isChecked())
                    self.axes_Q2.hold(self.hold_cb.isChecked())
                elif self.axis_state == 2 and new_state == 2:
                    self.axes_Q1.hold(self.hold_cb.isChecked())
                    self.axes_Q4.hold(self.hold_cb.isChecked())
                else:
                    self.remove_subplots()
            else:
                self.remove_subplots()
        
        # If show negative box is unchecked
        if not self.trunc_cb.isChecked():
            self.add_main()
            self.axes.plot(self.input_x, self.y, self.plot_symbol)
            if not self.logx_cb.isChecked() and not self.logy_cb.isChecked():
                self.axes.set_xscale('linear')
                self.axes.set_yscale('linear')
            elif self.logx_cb.isChecked() and not self.logy_cb.isChecked():
                self.axes.set_xscale('log')
                self.axes.set_yscale('linear')
            elif not self.logx_cb.isChecked() and self.logy_cb.isChecked():
                self.axes.set_xscale('linear')
                self.axes.set_yscale('log')
            else:
                self.axes.set_xscale('log')
                self.axes.set_yscale('log')
        else:
            # Linear plot
            #if not self.logx_cb.isChecked() and not self.logy_cb.isChecked():
            if new_state == 0:
                self.add_main()
                self.axes.plot(self.input_x,self.y,self.plot_symbol)
                
            # Log x, linear y plot
            #elif self.logx_cb.isChecked() and not self.logy_cb.isChecked():
            elif new_state == 1:
                if not self.trunc_cb.isChecked():
                    self.add_main()
                    self.axes.semilogx(self.input_x,self.y,self.plot_symbol)
                else:
                    self.trunc_logx()
                    
            # Linear x, log y plot
            #elif not self.logx_cb.isChecked() and self.logy_cb.isChecked():
            elif new_state == 2:
                if not self.trunc_cb.isChecked():
                    self.add_main()
                    self.axes.semilogy(self.input_x,self.y,self.plot_symbol)
                else:
                    self.trunc_logy()
                    
            # Log-log plot
            else:
                if not self.trunc_cb.isChecked():
                    self.add_main()
                    self.axes.loglog(self.input_x,self.y,self.plot_symbol)
                else:
                    self.trunc_loglog()
        
        # Add grid if grid checkbox is checked
        if self.axis_state == 0:
            self.axes.grid(self.grid_cb.isChecked())
        else:
            if hasattr(self, 'axes_Q1'):
                self.axes_Q1.grid(self.grid_cb.isChecked())
            if hasattr(self, 'axes_Q2'):
                self.axes_Q2.grid(self.grid_cb.isChecked())
            if hasattr(self, 'axes_Q3'):
                self.axes_Q3.grid(self.grid_cb.isChecked())
            if hasattr(self, 'axes_Q4'):
                self.axes_Q4.grid(self.grid_cb.isChecked())
        
        self.axes.set_xlabel('$x$')
        self.axes.set_ylabel('$f(x)$')
        self.canvas.draw()
        self.guardarImagen()
        
        
    def remove_subplots(self):
        # Remove all subplots and axis flip flags
        if hasattr(self, 'axes_Q1'):
            self.fig.delaxes(self.axes_Q1)
            del self.axes_Q1
        if hasattr(self, 'axes_Q2'):
            self.fig.delaxes(self.axes_Q2)
            del self.axes_Q2
            if hasattr(self, 'flip_Q2'):
                del self.flip_Q2
        if hasattr(self, 'axes_Q3'):
            self.fig.delaxes(self.axes_Q3)
            del self.axes_Q3
            del self.flip_Q3
        if hasattr(self, 'axes_Q4'):
            self.fig.delaxes(self.axes_Q4)
            del self.axes_Q4
            if hasattr(self, 'flip_Q4'):
                del self.flip_Q4
    
    def add_main(self):
        # Reinsert the main plot
        if self.axis_state > 0:
            self.remove_subplots()
            self.axes = self.fig.add_subplot(111)
            self.axis_state = 0
            
    def create_menu(self):
        exitAction = QAction('Quit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
        
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        
        save_plot_action = self.create_action("&Save plot",
            shortcut = "Ctrl+S", slot = self.save_plot, 
            tip = "Save image to file")
        import_data_action = self.create_action("&Import data",
            shortcut = "Ctrl+I", slot = self.import_data,
            tip = "Import data from file")
        fileMenu.addAction(save_plot_action)
        fileMenu.addAction(import_data_action)
        fileMenu.addAction(exitAction)
        
        helpMenu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", 
            shortcut = 'F1', slot = self.on_about, 
            tip = 'About CutePlot')
        helpMenu.addAction(about_action)

    def create_action(self, text, slot = None, shortcut = None, 
                        icon = None, tip = None, checkable = False, 
                        signal = "triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action
        
    def save_plot(self):
        file_choices = "PNG (*.png)"
        path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '', file_choices))
        if path:
            self.canvas.print_figure(path, dpi = self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def import_data(self):
        file_choices = "*.csv;;*.txt;;*.tab;;*.dat;;*.*"
        self.path = QFileDialog.getOpenFileName(self, 'Import data', '', file_choices)
        if self.path:
            datafile = open(self.path[0], 'r')
            if datafile:
                self.is_data = True
                delimiter = ','
                input_xy = [map(float, line.strip().split(delimiter)) for line in datafile]
                self.input_x, self.y = [[row[col] for row in input_xy] for col in [0, 1]]
                datafile.close()
                self.statusBar().showMessage('Imported data', 2000)
                self.on_draw(self.is_data)
                
    def on_about(self):
        msg = """<center><b>CutePlot v. 0.1</b></center>
        <center>Free, open-source plotting program,<br />
        written in Python (PySide/Qt + matplotlib).</center>
        <center>(c) Jack Peterson, 2012</center>
        """
        QMessageBox.about(self, "About", msg.strip())
        
    def quad_check(self):
        # Q = quadrant
        Q1 = False
        Q2 = False
        Q3 = False
        Q4 = False
        
        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1 = True
            elif self.input_x[j] < 0 and self.y[j] > 0:
                Q2 = True
            elif self.input_x[j] < 0 and self.y[j] < 0:
                Q3 = True
            elif self.input_x[j] > 0 and self.y[j] < 0:
                Q4 = True
      
      
        if (Q3 or (Q2 and Q4) or ((Q2 or Q4) and self.axis_state == 3)) and self.logx_cb.isChecked() and self.logy_cb.isChecked():
            new_state = 3
        elif (Q2 and self.logx_cb.isChecked()) or (self.hold_cb.isChecked() and self.axis_state == 1):
            new_state = 1
        elif (Q4 and self.logy_cb.isChecked()) or (self.hold_cb.isChecked() and self.axis_state == 2):
            new_state = 2
        else:
            new_state = 0
        
        return new_state
        
    def trunc_logx(self):
        # Q = quadrant
        Q1_x = []
        Q1_y = []
        Q2_x = []
        Q2_y = []
        
        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1_x.append(self.input_x[j])
                Q1_y.append(self.y[j])
            elif self.input_x[j] < 0 and self.y[j] > 0:
                Q2_x.append(-self.input_x[j])
                Q2_y.append(self.y[j])
        
        # If only Q1 is populated, then use an ordinary semilogx plot
        if Q2_x == [] and not self.hold_cb.isChecked():
            self.add_main()
            self.axes.semilogx(self.input_x, self.y, self.plot_symbol)
        
        # Otherwise, create a truncated plot
        else:
            # Remove main axes
            if self.axis_state == 0:
                self.fig.delaxes(self.axes)
            
            if self.axis_state == 2 or self.axis_state == 3:
                self.axis_state = 3
            else:
                self.axis_state = 1
            
            # Create 2 subplots
            self.axes_Q1 = self.fig.add_subplot(122)
            self.axes_Q2 = self.fig.add_subplot(121)
            self.axes_Q1.autoscale(enable = True)
            self.axes_Q2.autoscale(enable = True)
            self.axes_Q1.semilogx(Q1_x, Q1_y, self.plot_symbol)
            self.axes_Q2.semilogx(Q2_x, Q2_y, self.plot_symbol)
                                
            # Reverse Q2 x-axis
            if not hasattr(self, 'flip_Q2'):
                self.flip_Q2 = True
                self.axes_Q2.set_xlim(self.axes_Q2.get_xlim()[::-1])
            
            # Set axis tickmarks at powers of 10
            # Q1 axes
            if Q1_x == [] and not self.hold_cb.isChecked():
                self.axes_Q1.set_xticklabels([])
            else:
                try:
                    x_UB_Q1 = int(ceil(log10(max(Q1_x))))
                    x_LB_Q1 = int(floor(log10(min(Q1_x))))
                except:
                    x_UB_Q1 = 2
                    x_LB_Q1 = -1
                Q1_xlabels = []
                for i in range(x_LB_Q1, x_UB_Q1 + 1):
                    Q1_xlabels.append('$10^{%s}$' % str(i))
                self.axes_Q1.set_xticklabels(Q1_xlabels)
            self.axes_Q1.xaxis.tick_bottom()
            self.axes_Q1.yaxis.tick_right()
            
            # Q2 axes
            if Q2_x == [] and not self.hold_cb.isChecked():
                self.axes_Q2.set_xticklabels([])
            else:
                try:
                    x_UB_Q2 = int(ceil(log10(max(Q2_x))))
                    x_LB_Q2 = int(floor(log10(min(Q2_x))))
                except:
                    x_UB_Q2 = 2
                    x_LB_Q2 = -1
                Q2_xlabels = []
                for i in range(x_LB_Q2, x_UB_Q2 + 1):
                    Q2_xlabels.append('$-10^{%s}$' % str(i))
                self.axes_Q2.set_xticklabels(Q2_xlabels)
            self.axes_Q2.xaxis.tick_bottom()
            self.axes_Q2.yaxis.tick_left()
          
    def trunc_logy(self):
        # Q = quadrant
        Q1_x = []
        Q1_y = []
        Q4_x = []
        Q4_y = []
        
        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1_x.append(self.input_x[j])
                Q1_y.append(self.y[j])
            elif self.input_x[j] > 0 and self.y[j] < 0:
                Q4_x.append(self.input_x[j])
                Q4_y.append(-self.y[j])
        
        # If only Q1 is populated, then use an ordinary semilogy plot
        if Q4_x == [] and not self.hold_cb.isChecked():
            self.add_main()
            self.axes.semilogy(self.input_x, self.y, self.plot_symbol)
        
        # Otherwise, create a truncated plot
        else:
            # Remove main axes
            if self.axis_state == 0:
                self.fig.delaxes(self.axes)
                
            if self.axis_state == 1 or self.axis_state == 3:
                self.axis_state = 3
            else:
                self.axis_state = 2
            
            # Create 2 subplots
            self.axes_Q1 = self.fig.add_subplot(211)
            self.axes_Q4 = self.fig.add_subplot(212)
            self.axes_Q1.autoscale(enable = True)
            self.axes_Q4.autoscale(enable = True)
            self.axes_Q1.semilogy(Q1_x, Q1_y, self.plot_symbol)
            self.axes_Q4.semilogy(Q4_x, Q4_y, self.plot_symbol)
                                
            # Reverse Q4 y-axis
            if not hasattr(self, 'flip_Q4'):
                self.flip_Q4 = True
                self.axes_Q4.set_ylim(self.axes_Q4.get_ylim()[::-1])
            
            # Set axis tickmarks at powers of 10
            # Q1 axes
            if Q1_x == [] and not self.hold_cb.isChecked():
                self.axes_Q1.set_yticklabels([])
            else:
                try:
                    y_UB_Q1 = int(ceil(log10(max(Q1_y))))
                    y_LB_Q1 = int(floor(log10(min(Q1_y))))
                except:
                    y_UB_Q1 = 2
                    y_LB_Q1 = -1
                Q1_ylabels = []
                for i in range(y_LB_Q1, y_UB_Q1 + 1):
                    Q1_ylabels.append('$10^{%s}$' % str(i))
                self.axes_Q1.set_yticklabels(Q1_ylabels)
            self.axes_Q1.xaxis.tick_top()
            self.axes_Q1.yaxis.tick_right()
            
            # Q4 axes
            if Q4_x == [] and not self.hold_cb.isChecked():
                self.axes_Q4.set_yticklabels([])
            else:
                try:
                    y_UB_Q4 = int(ceil(log10(max(Q4_y))))
                    y_LB_Q4 = int(floor(log10(min(Q4_y))))
                except:
                    y_UB_Q4 = 2
                    y_LB_Q4 = -1
                Q4_ylabels = []
                for i in range(y_LB_Q4, y_UB_Q4 + 1):
                    Q4_ylabels.append('$-10^{%s}$' % str(i))
                self.axes_Q4.set_yticklabels(Q4_ylabels)
            self.axes_Q4.xaxis.tick_bottom()
            self.axes_Q4.yaxis.tick_right()
          
        
    def trunc_loglog(self):
        # Q = quadrant
        Q1_x = []
        Q1_y = []
        Q2_x = []
        Q2_y = []
        Q3_x = []
        Q3_y = []
        Q4_x = []
        Q4_y = []
        
        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1_x.append(self.input_x[j])
                Q1_y.append(self.y[j])
            elif self.input_x[j] < 0 and self.y[j] > 0:
                Q2_x.append(-self.input_x[j])
                Q2_y.append(self.y[j])
            elif self.input_x[j] < 0 and self.y[j] < 0:
                Q3_x.append(-self.input_x[j])
                Q3_y.append(-self.y[j])
            elif self.input_x[j] > 0 and self.y[j] < 0:
                Q4_x.append(self.input_x[j])
                Q4_y.append(-self.y[j])
        
        # If only Q1 is populated, then use an ordinary loglog plot
        if Q2_x == [] and Q3_x == [] and Q4_x == [] and not self.hold_cb.isChecked():
            self.add_main()
            self.axes.loglog(self.input_x, self.y, self.plot_symbol)
        
        # Otherwise, create a truncated plot
        else:
            # Remove main axes
            if self.axis_state == 0:
                self.fig.delaxes(self.axes)
            self.axis_state = 3
            
            # Create 4 subplots
            self.axes_Q1 = self.fig.add_subplot(222)
            self.axes_Q2 = self.fig.add_subplot(221)
            self.axes_Q3 = self.fig.add_subplot(223)
            self.axes_Q4 = self.fig.add_subplot(224)
            self.axes_Q1.autoscale(enable = True)
            self.axes_Q2.autoscale(enable = True)
            self.axes_Q3.autoscale(enable = True)
            self.axes_Q4.autoscale(enable = True)
            self.axes_Q1.loglog(Q1_x, Q1_y, self.plot_symbol)
            self.axes_Q2.loglog(Q2_x, Q2_y, self.plot_symbol)
            self.axes_Q3.loglog(Q3_x, Q3_y, self.plot_symbol)
            self.axes_Q4.loglog(Q4_x, Q4_y, self.plot_symbol)
            
            if not hasattr(self, 'flip_Q3'):
                self.flip_Q3 = True
            
                # Reverse Q2 x-axis
                self.axes_Q2.set_xlim(self.axes_Q2.get_xlim()[::-1])    
                
                # Reverse Q3 x- and y-axes
                self.axes_Q3.set_xlim(self.axes_Q3.get_xlim()[::-1])
                self.axes_Q3.set_ylim(self.axes_Q3.get_ylim()[::-1])
                
                # Reverse Q4 y-axis
                self.axes_Q4.set_ylim(self.axes_Q4.get_ylim()[::-1])
            
            # Set axis tickmarks at powers of 10
            # Q1 axes
            if Q1_x == [] and not self.hold_cb.isChecked():
                self.axes_Q1.set_xticklabels([])
                self.axes_Q1.set_yticklabels([])
            else:
                try:
                    x_UB_Q1 = int(ceil(log10(max(Q1_x))))
                    y_UB_Q1 = int(ceil(log10(max(Q1_y))))
                    x_LB_Q1 = int(floor(log10(min(Q1_x))))
                    y_LB_Q1 = int(floor(log10(min(Q1_y))))
                except:
                    x_UB_Q1 = 2
                    y_UB_Q1 = 2
                    x_LB_Q1 = -1
                    y_LB_Q1 = -1
                Q1_xlabels = []
                Q1_ylabels = []
                for i in range(x_LB_Q1, x_UB_Q1 + 1):
                    Q1_xlabels.append('$10^{%s}$' % str(i))
                for i in range(y_LB_Q1, y_UB_Q1 + 1):
                    Q1_ylabels.append('$10^{%s}$' % str(i))
                self.axes_Q1.set_xticklabels(Q1_xlabels)
                self.axes_Q1.set_yticklabels(Q1_ylabels)
            self.axes_Q1.xaxis.tick_top()
            self.axes_Q1.yaxis.tick_right()
            
            # Q2 axes
            if Q2_x == [] and not self.hold_cb.isChecked():
                self.axes_Q2.set_xticklabels([])
                self.axes_Q2.set_yticklabels([])
            else:
                try:
                    x_UB_Q2 = int(ceil(log10(max(Q2_x))))
                    y_UB_Q2 = int(ceil(log10(max(Q2_y))))
                    x_LB_Q2 = int(floor(log10(min(Q2_x))))
                    y_LB_Q2 = int(floor(log10(min(Q2_y))))
                except:
                    x_UB_Q2 = 2
                    y_UB_Q2 = 2
                    x_LB_Q2 = -1
                    y_LB_Q2 = -1
                Q2_xlabels = []
                Q2_ylabels = []
                for i in range(x_LB_Q2, x_UB_Q2 + 1):
                    Q2_xlabels.append('$-10^{%s}$' % str(i))
                for i in range(y_LB_Q2, y_UB_Q2 + 1):
                    Q2_ylabels.append('$10^{%s}$' % str(i))
                self.axes_Q2.set_xticklabels(Q2_xlabels)
                self.axes_Q2.set_yticklabels(Q2_ylabels)
            self.axes_Q2.xaxis.tick_top()
            self.axes_Q2.yaxis.tick_left()
        
            # Q3 axes
            if Q3_x == [] and not self.hold_cb.isChecked():
                self.axes_Q3.set_xticklabels([])
                self.axes_Q3.set_yticklabels([])
            else:
                try:
                    x_UB_Q3 = int(ceil(log10(max(Q3_x))))
                    y_UB_Q3 = int(ceil(log10(max(Q3_y))))
                    x_LB_Q3 = int(floor(log10(min(Q3_x))))
                    y_LB_Q3 = int(floor(log10(min(Q3_y))))
                except:
                    x_UB_Q3 = 2
                    y_UB_Q3 = 2
                    x_LB_Q3 = -1
                    y_LB_Q3 = -1
                Q3_xlabels = []
                Q3_ylabels = []
                for i in range(x_LB_Q3, x_UB_Q3 + 1):
                    Q3_xlabels.append('$-10^{%s}$' % str(i))
                for i in range(y_LB_Q3, y_UB_Q3 + 1):
                    Q3_ylabels.append('$-10^{%s}$' % str(i))
                self.axes_Q3.set_xticklabels(Q3_xlabels)
                self.axes_Q3.set_yticklabels(Q3_ylabels)
            self.axes_Q3.xaxis.tick_bottom()
            self.axes_Q3.yaxis.tick_left()
                
            # Q4 axes
            if Q4_x == [] and not self.hold_cb.isChecked():
                self.axes_Q4.set_xticklabels([])
                self.axes_Q4.set_yticklabels([])
            else:
                try:
                    x_UB_Q4 = int(ceil(log10(max(Q4_x))))
                    y_UB_Q4 = int(ceil(log10(max(Q4_y))))
                    x_LB_Q4 = int(floor(log10(min(Q4_x))))
                    y_LB_Q4 = int(floor(log10(min(Q4_y))))
                except:
                    x_UB_Q4 = 2
                    y_UB_Q4 = 2
                    x_LB_Q4 = -1
                    y_LB_Q4 = -1
                Q4_xlabels = []
                Q4_ylabels = []
                for i in range(x_LB_Q4, x_UB_Q4 + 1):
                    Q4_xlabels.append('$10^{%s}$' % str(i))
                for i in range(y_LB_Q4, y_UB_Q4 + 1):
                    Q4_ylabels.append('$-10^{%s}$' % str(i))
                self.axes_Q4.set_xticklabels(Q4_xlabels)
                self.axes_Q4.set_yticklabels(Q4_ylabels)
            self.axes_Q4.xaxis.tick_bottom()
            self.axes_Q4.yaxis.tick_right()
            
    
    def guardarImagen(self):
        path = os.path.abspath("untitled.png")  
        self.canvas.resize(460,261 )     
        self.canvas.print_figure(path, dpi = self.dpi)
        self.statusBar().showMessage('Saved to %s' % path, 2000)
        self.canvas.resize(560,361 ) 
예제 #28
0
def plot_filter_freqs():
    '''
    Shows the various frequencies within the system, and what the filter does.
    '''
    # Each bin is one sample; sampled at 50Mhz
    nbins = 3200

    # Time of each sample, in us
    tt = np.arange(0, nbins / 50., 1 / 50.)
    # 70MHz local oscillator signal
    y70 = np.sin(2 * np.pi * tt * 70)
    fft70 = np.fft.fft(y70, n=nbins)
    # 140MHz - LO's first harmonic
    y140 = np.sin(2 * np.pi * tt * 140)
    fft140 = np.fft.fft(y140, n=nbins)

    # Reference chirp used for actual pik1 dechirping
    ref_chirp = pik1_utils.generate_reference_chirp()
    y_ref = np.zeros(nbins)
    y_ref[100:100 + len(ref_chirp)] = ref_chirp
    fft_ref = np.fft.fft(y_ref, n=nbins)

    # theoretical reference chirp
    theoretical_chirp = pik1_utils.generate_theoretical_chirp()
    y_theory = np.zeros(nbins)
    y_theory[100:100 + len(theoretical_chirp)] = theoretical_chirp
    fft_theory = np.fft.fft(y_theory, n=nbins)

    # Frequency of fft bins, in MHz
    fftfreq = np.fft.fftfreq(nbins, 1 / 50.)

    # ideal chirp frequency content
    fft_ideal = [
        1.0 if 2.5 <= np.abs(elem) <= 17.5 else 0.0 for elem in fftfreq
    ]

    # Hanning filter
    hfilter = pik1_utils.generate_hfilter(nbins)

    fig = Figure((15, 3.5))
    canvas = FigureCanvas(fig)
    ax = fig.add_axes([0.05, 0.25, 0.9, 0.7])

    ax.plot(fftfreq,
            np.abs(fft_ref) / np.max(np.abs(fft_ref)),
            linewidth=1,
            color='black',
            label='pik1 reference chirp')
    ax.plot(fftfreq,
            np.abs(fft_theory) / np.max(np.abs(fft_theory)),
            linewidth=2,
            color='darkgrey',
            label='theoretical reference chirp')
    ax.plot(fftfreq,
            np.abs(fft_ideal) / np.max(np.abs(fft_ideal)),
            linewidth=2,
            color='lightgrey',
            label='theoretical reference chirp')
    ax.plot(fftfreq,
            np.abs(fft70) / np.max(np.abs(fft70)),
            linewidth=2,
            color='blue',
            label='FFT of 70MHz signal')
    ax.plot(fftfreq,
            np.abs(fft140) / np.max(np.abs(fft140)),
            linewidth=2,
            color='blue',
            label='FFT of 1st harmonic of LO')
    ax.plot(fftfreq,
            hfilter / np.max(hfilter),
            linewidth=2,
            color='red',
            label='Hamming filter')
    ax.set_ylim([0, 1.05])
    ax.set_xlim([-25, 25])
    ax.set_xlabel('Frequency (MHz)', fontsize=24)
    #ax.legend()
    ax.tick_params(which='both',
                   bottom=True,
                   top=False,
                   left=False,
                   right=False,
                   labelbottom=True,
                   labeltop=False,
                   labelleft=False,
                   labelright=False,
                   labelsize=18)
    for side in ['top', 'left', 'right']:
        ax.spines[side].set_visible(False)

    canvas.print_figure('../FinalReport/figures/filter_frequencies.png')
예제 #29
0
파일: View.py 프로젝트: SeisSol/SeisSol
class View(QWidget):

  def __init__(self, parent = None):
    super(View, self).__init__(parent)
    
    self.__watchdog = Watchdog.Watchdog()
    self.__watchdog.fileChanged.connect(self.refreshAll)

    self.figure = plt.figure()
    self.canvas = FigureCanvas(self.figure)
    self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)    
    toolbar = NavigationToolbar(self.canvas, self)
    
    self.navigationLayout = QHBoxLayout()
    
    layout = QHBoxLayout(self)
    self.navigations = []
    self.addNavigation(True)
    
    self.filters = [ Filters.Lowpass(), Filters.Deconvolve(), Filters.Rotate() ]
    filterLayout = QVBoxLayout()    
    for f in self.filters:
      filterLayout.addWidget(f)
      f.filterChanged.connect(self.plot)
    filterLayout.addStretch()
    
    addIcon = QIcon.fromTheme('list-add')
    addNaviButton = QPushButton(addIcon, 'Add navigation', self)
    addNaviButton.clicked.connect(self.addNavigation)
    
    self.maxFreq = QDoubleSpinBox(self)
    self.maxFreq.setValue(10.0)
    self.maxFreq.setVisible(False)
    self.maxFreq.valueChanged.connect(self.plot)
    spectrumIcon = QIcon.fromTheme('network-wireless')
    self.spectrum = QPushButton(spectrumIcon, 'Spectrum', self)
    self.spectrum.setCheckable(True)
    self.spectrum.clicked.connect(self.plot)
    self.spectrum.toggled.connect(self.maxFreq.setVisible)
    self.diff = QPushButton('Diff', self)
    self.diff.setCheckable(True)
    self.diff.clicked.connect(self.plot)
    self.diff.clicked.connect(self.spectrum.setHidden)
    self.spectrum.toggled.connect(self.diff.setHidden)
    
    autoRefresh = QPushButton(QIcon.fromTheme('view-refresh'), 'Auto', self)
    autoRefresh.setCheckable(True)
    autoRefresh.clicked.connect(self.__watchdog.toggle)
    
    saveAll = QPushButton(QIcon.fromTheme('document-save'), '', self)
    saveAll.clicked.connect(self.savePlots)

    toolLayout = QHBoxLayout()
    toolLayout.addWidget(addNaviButton)
    toolLayout.addWidget(self.diff)
    toolLayout.addWidget(self.spectrum)
    toolLayout.addWidget(self.maxFreq)
    toolLayout.addWidget(autoRefresh)
    toolLayout.addWidget(saveAll)
    toolLayout.addWidget(toolbar)
    plotLayout = QVBoxLayout()
    plotLayout.addLayout(toolLayout)
    plotLayout.addWidget(self.canvas)
    layout.addLayout(self.navigationLayout)
    layout.addLayout(plotLayout)
    layout.addLayout(filterLayout)
    
  def addNavigation(self, noclose = False):
    navigation = Navigation.Navigation(noclose)
    navigation.activeItemChanged.connect(self.plot)
    navigation.folderChanged.connect(self.navigationFolderChanged)
    navigation.close.connect(self.closeNavigation)
    navigation.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum)
    self.navigationLayout.addWidget(navigation)
    self.navigations.append(navigation)

  def navigationFolderChanged(self, oldFolder, newFolder):
    self.__watchdog.removeFolder(oldFolder)
    self.__watchdog.addFolder(newFolder)
    
  def closeNavigation(self, widget):
    self.navigations.remove(widget)
    self.navigationLayout.removeWidget(widget)
    widget.deleteLater()
    self.plot()
    
  def refreshAll(self):
    for navigation in self.navigations:
        navigation.refreshFolder()

  def plot(self):
    wfc = [wf for nav in self.navigations for wf in nav.getActiveWaveforms()]
    for filt in self.filters:
      if filt.isChecked():
        for wf in wfc:
          filt.apply(wf)
          
    if self.diff.isChecked() and len(wfc) > 0:
      wf0 = wfc.pop()
      for nWf, wf in enumerate(wfc):
        wfc[nWf].subtract(wf0)

    names = set([name for wf in wfc for name in wf.waveforms.iterkeys()])
    numPlots = len(names)

    self.figure.clear()
    if numPlots > 0:
      names = list(names)
      names.sort()

      numRows = math.ceil(math.sqrt(numPlots));
      numCols = math.ceil(numPlots / numRows)
      subplots = dict()
      for i in range(len(names)):
        subplots[ names[i] ] = self.figure.add_subplot(numRows, numCols, i+1)

      for nWf, wf in enumerate(wfc):
        for name, waveform in wf.waveforms.iteritems():
          p = subplots[name]
          if self.spectrum.isChecked():
            n = len(waveform)
            dt = wf.time[1]-wf.time[0] # assume equally spaced samples
            f = scipy.fftpack.fftfreq(n, dt)
            W = dt * scipy.fftpack.fft(waveform)
            maxFreqIndices = numpy.argwhere(f > self.maxFreq.value())
            L = maxFreqIndices[0] if len(maxFreqIndices) > 0 else n/2
            p.loglog(f[1:L], numpy.absolute(W[1:L]), label=str(nWf))
            p.set_xlabel('f [Hz]')
          elif self.diff.isChecked():
            p.plot(wf.time, waveform, label='{}-0'.format(nWf+1))
            p.set_xlabel('t (s)')
          else:
            p.plot(wf.time, waveform, label=str(nWf))
            p.set_xlabel('t (s)')
          p.set_ylabel(name)

      self.figure.tight_layout()

    for i in range(len(names)):
      subplots[ names[i] ].legend(prop={'size':8}, frameon=False)
    self.canvas.draw()
  
  def savePlots(self):
    filetypes = self.canvas.get_supported_filetypes_grouped()
    defaultFiletype = self.canvas.get_default_filetype()
    filters = []
    selectedFilter = ''
    for name, extensions in sorted(filetypes.iteritems()):
      filtr = '{0} ({1})'.format(name, ' '.join(['*.{0}'.format(ext) for ext in extensions]))
      if defaultFiletype in extensions:
        selectedFilter = filtr
      filters.append(filtr)
    fileName, filtr = QFileDialog.getSaveFileNameAndFilter(self, 'Choose a save location.', '', ';;'.join(filters), selectedFilter)
    fileName = os.path.splitext(str(fileName))[0]
    extension = re.search(r'\*(\.[a-zA-Z]+)', str(filtr)).group(1)
    
    maxRow = min([nav.numberOfRows() for nav in self.navigations])
    for row in range(maxRow):
      for nav in self.navigations:
        nav.selectWaveformAt(row)
      self.plot()
      self.canvas.print_figure('{0}{1:03}{2}'.format(fileName, row+1, extension))
예제 #30
0
class InteractiveDetector(QMainWindow):
    """
    Click on a point to select and highlight it -- the data that
    generated the point will be shown in the lower axes.  Use the 'n'
    and 'p' keys to browse through the next and previous points
    @see http://matplotlib.org/examples/event_handling/data_browser.html
    @see http://matplotlib.org/examples/event_handling/poly_editor.html
    """
    def __init__(self,
                 Seq,
                 hpe,
                 importer,
                 filename_detection,
                 filename_log,
                 subset_idxs,
                 start_idx,
                 parent=None):
        super(InteractiveDetector, self).__init__(parent)
        self.setWindowTitle('Detection Tool')
        self.dpi = 100
        self.panned = False
        self.lastind = 0
        self._ind = None
        self.epsilon = 15
        self.press = (0, 0, 0, 0)
        self.hpe = hpe
        self.importer = importer
        self.path_prefix = ''
        if filename_log is not None:
            if os.path.exists(filename_log):
                self.file_log = open(filename_log, 'a')
            else:
                self.file_log = open(filename_log, 'w')
        else:
            self.file_log = None
        self.start_time = time.time()

        self.subset_idxs = subset_idxs

        if len(self.subset_idxs) > 0:
            self.curFrame = self.subset_idxs[0]
        else:
            self.curFrame = 0
        self._seq = Seq
        self.plots_xy = []
        self.plots_xz = []
        self.plots_yz = []
        self.plots_color = []

        self.getCurrentStatus(filename_detection)

        if start_idx != 0:
            if len(self.subset_idxs) > 0:
                if start_idx in self.subset_idxs:
                    self.curFrame = start_idx
                else:
                    raise UserWarning("Unknown start_idx, not in subset!")
            else:
                self.curFrame = start_idx

        if ~numpy.allclose(self._seq.data[self.curFrame].com, 0.):
            self.curData = self.importer.joint3DToImg(
                self._seq.data[self.curFrame].com).reshape((1, 3))
        else:
            self.curData = numpy.zeros((1, 3))

        self.filename_det = filename_detection

        self.initGUI()
        self.connectEvents()

        self.showCurrent()

    def initGUI(self):
        self.main_frame = QWidget(self)

        # XY plot and toolbar
        self.fig_xy = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas_xy = FigureCanvas(self.fig_xy)
        self.canvas_xy.setParent(self.main_frame)
        self.ax_xy = self.fig_xy.add_subplot(111)
        self.ax_xy.set_title('Click and drag a point to move it')
        box = self.ax_xy.get_position()
        self.ax_xy.set_position(
            [box.x0, box.y0 + box.height * 0.1, box.width, box.height * 0.9])
        self.mpl_toolbar_xy = NavigationToolbar(self.canvas_xy,
                                                self.main_frame)

        def pan_callback():
            self.panned = True

        self.fig_xy.canvas.toolbar.actions()[4].triggered.connect(pan_callback)

        # XZ, YZ plot and toolbar
        self.fig_xz_yz = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas_xz_yz = FigureCanvas(self.fig_xz_yz)
        self.canvas_xz_yz.setParent(self.main_frame)
        gs = matplotlib.gridspec.GridSpec(2, 1)
        self.ax_xz = self.fig_xz_yz.add_subplot(gs[0])
        self.ax_xz.axes.set_frame_on(False)
        self.ax_yz = self.fig_xz_yz.add_subplot(gs[1])
        self.ax_yz.axes.set_frame_on(False)
        self.mpl_toolbar_xz_yz = NavigationToolbar(self.canvas_xz_yz,
                                                   self.main_frame)

        # optional color plot and toolbar
        if hasattr(self._seq.data[self.curFrame], 'colorFileName'):
            self.fig_color = Figure((5.0, 4.0), dpi=self.dpi)
            self.canvas_color = FigureCanvas(self.fig_color)
            self.canvas_color.setParent(self.main_frame)
            self.ax_color = self.fig_color.add_subplot(111)
            self.ax_color.axes.set_frame_on(False)
            self.mpl_toolbar_color = NavigationToolbar(self.canvas_color,
                                                       self.main_frame)
        else:
            self.ax_color = None

        # Layout with posebit controls
        hbox_pb_controls = QHBoxLayout()

        self.prevButton = QPushButton('Previous', self.main_frame)
        self.connect(self.prevButton, SIGNAL('clicked()'),
                     self.prevButton_callback)
        hbox_pb_controls.addWidget(self.prevButton)

        self.pointcloudButton = QPushButton('3D View', self.main_frame)
        self.connect(self.pointcloudButton, SIGNAL('clicked()'),
                     self.pointcloudButton_callback)
        hbox_pb_controls.addWidget(self.pointcloudButton)

        self.nextButton = QPushButton('Next', self.main_frame)
        self.connect(self.nextButton, SIGNAL('clicked()'),
                     self.nextButton_callback)
        hbox_pb_controls.addWidget(self.nextButton)

        hbox_plots = QHBoxLayout()

        vbox_xy = QVBoxLayout()
        vbox_xy.addWidget(self.canvas_xy)
        vbox_xy.addWidget(self.mpl_toolbar_xy)
        hbox_plots.addLayout(vbox_xy)

        vbox_xz_yz = QVBoxLayout()
        vbox_xz_yz.addWidget(self.canvas_xz_yz)
        vbox_xz_yz.addWidget(self.mpl_toolbar_xz_yz)
        hbox_plots.addLayout(vbox_xz_yz)

        if self.ax_color is not None:
            vbox_color = QVBoxLayout()
            vbox_color.addWidget(self.canvas_color)
            vbox_color.addWidget(self.mpl_toolbar_color)
            hbox_plots.addLayout(vbox_color)

        vbox_all = QVBoxLayout()
        vbox_all.addLayout(hbox_plots)
        sep = QFrame(self.main_frame)
        sep.setFrameShape(QFrame.HLine)
        sep.setFrameShadow(QFrame.Sunken)
        vbox_all.addWidget(sep)
        vbox_all.addLayout(hbox_pb_controls)

        self.main_frame.setLayout(vbox_all)
        self.setCentralWidget(self.main_frame)

    def showCurrent(self):
        dm = self.importer.loadDepthMap(self.path_prefix +
                                        self._seq.data[self.curFrame].fileName)
        if ~numpy.allclose(self.curData, 0.):
            dm[dm < self.curData[0, 2] - self._seq.config['cube'][2] /
               2.] = self.curData[0, 2] + self._seq.config['cube'][2] / 2.
            dm[dm > self.curData[0, 2] + self._seq.config['cube'][2] /
               2.] = self.curData[0, 2] + self._seq.config['cube'][2] / 2.

        # XY plot
        if self.panned is False:
            xstart = numpy.where(~numpy.isclose(
                dm, self.curData[0, 2] +
                self._seq.config['cube'][2] / 2.))[1].min()
            xend = numpy.where(~numpy.isclose(
                dm, self.curData[0, 2] +
                self._seq.config['cube'][2] / 2.))[1].max()
            ystart = numpy.where(~numpy.isclose(
                dm, self.curData[0, 2] +
                self._seq.config['cube'][2] / 2.))[0].min()
            yend = numpy.where(~numpy.isclose(
                dm, self.curData[0, 2] +
                self._seq.config['cube'][2] / 2.))[0].max()
        else:
            xstart, xend = self.ax_xy.get_xlim()
            yend, ystart = self.ax_xy.get_ylim(
            )  # axis is flipped after imshow
        self.ax_xy.cla()
        self.text = self.ax_xy.text(0.05,
                                    0.95,
                                    'joint: none',
                                    transform=self.ax_xy.transAxes,
                                    va='top')
        self.frame = self.ax_xy.text(0.55,
                                     0.95,
                                     'frame: none',
                                     transform=self.ax_xy.transAxes,
                                     va='top')
        self.selected, = self.ax_xy.plot([0], [0],
                                         'o',
                                         ms=12,
                                         alpha=0.4,
                                         color='yellow',
                                         visible=False)
        self.frame.set_text('frame: {}/{}'.format(self.curFrame,
                                                  len(self._seq.data) - 1))
        self.ax_xy.imshow(dm, cmap='CMRmap', interpolation='none')
        self.ax_xy.set_xlabel('x')
        self.ax_xy.set_ylabel('y')
        self.plots_xy = []
        for i in range(self.curData.shape[0]):
            d, = self.ax_xy.plot(self.curData[i, 0],
                                 self.curData[i, 1],
                                 c='r',
                                 marker='o',
                                 markersize=8)
            self.plots_xy.append(d)

        self.ax_xy.set_xlim([xstart, xend])
        self.ax_xy.set_ylim([yend, ystart])

        def format_coord(x, y):
            numrows, numcols = dm.shape
            col = int(numpy.rint(x))
            row = int(numpy.rint(y))
            if 0 <= col < numcols and 0 <= row < numrows:
                z = dm[row, col]
                return 'x=%d,y=%d,z=%d' % (x, y, z)
            else:
                return 'x=%d,y=%d' % (x, y)

        self.ax_xy.format_coord = format_coord

        # XZ plot
        self.ax_xz.cla()
        xz = numpy.min(dm, axis=0)
        self.ax_xz.plot(numpy.arange(dm.shape[1]), xz)
        self.ax_xz.set_xlabel('x')
        self.ax_xz.set_ylabel('z')
        pts = numpy.column_stack(
            (numpy.arange(dm.shape[1] + 2),
             numpy.concatenate([numpy.asarray([0]), xz,
                                numpy.asarray([0])])))
        polygon = Polygon(pts, True)
        p = PatchCollection([polygon], cmap='jet', alpha=0.4)
        p.set_array(numpy.array([50, 50, 50, 50]))
        self.ax_xz.add_collection(p)

        self.plots_xz = []
        for i in range(self.curData.shape[0]):
            d, = self.ax_xz.plot(self.curData[i, 0],
                                 self.curData[i, 2],
                                 c='r',
                                 marker='o',
                                 markersize=8)
            self.plots_xz.append(d)

        # YZ plot
        self.ax_yz.cla()
        yz = numpy.min(dm, axis=1)
        self.ax_yz.plot(numpy.arange(dm.shape[0]), yz)
        self.ax_yz.set_xlabel('y')
        self.ax_yz.set_ylabel('z')
        pts = numpy.column_stack(
            (numpy.arange(dm.shape[0] + 2),
             numpy.concatenate([numpy.asarray([0]), yz,
                                numpy.asarray([0])])))
        polygon = Polygon(pts, True)
        p = PatchCollection([polygon], cmap='jet', alpha=0.4)
        p.set_array(numpy.array([50, 50, 50, 50]))
        self.ax_yz.add_collection(p)

        self.plots_yz = []
        for i in range(self.curData.shape[0]):
            d, = self.ax_yz.plot(self.curData[i, 1],
                                 self.curData[i, 2],
                                 c='r',
                                 marker='o',
                                 markersize=8)
            self.plots_yz.append(d)

        # color image
        if self.ax_color:
            color = self.importer.loadColorImage(
                self.path_prefix + self._seq.data[self.curFrame].colorFileName)

            # XY plot
            self.ax_color.cla()
            if len(color.shape) == 3:
                self.ax_color.imshow(color.astype('uint8'),
                                     interpolation='none')
            else:
                self.ax_color.imshow(color, interpolation='none', cmap='gray')
            self.ax_color.set_xlabel('u')
            self.ax_color.set_ylabel('v')

            self.plots_color = []
            joint2D = self.importer.jointsDpt2DToCol2D(self.curData)
            for i in range(joint2D.shape[0]):
                d, = self.ax_color.plot(joint2D[i, 0],
                                        joint2D[i, 1],
                                        c='r',
                                        marker='o',
                                        markersize=8)
                self.plots_color.append(d)

        self.update()

    def showContext(self):
        dm = self.importer.loadDepthMap(self.path_prefix +
                                        self._seq.data[self.curFrame].fileName)
        dm[dm < self.curData[0, 2] - self._seq.config['cube'][2] / 2.] = \
            self.curData[0, 2] + self._seq.config['cube'][2] / 2.
        dm[dm > self.curData[0, 2] + self._seq.config['cube'][2] / 2.] = \
            self.curData[0, 2] + self._seq.config['cube'][2] / 2.

        self.ax_xz.cla()
        xz = dm[int(numpy.rint(self.curData[self.lastind, 1]))]
        self.ax_xz.plot(numpy.arange(dm.shape[1]), xz)
        self.plots_xz = []
        d, = self.ax_xz.plot(self.curData[self.lastind, 0],
                             self.curData[self.lastind, 2],
                             c='r',
                             marker='o',
                             markersize=8)
        self.plots_xz.append(d)
        self.ax_xz.set_xlim([
            self.curData[self.lastind, 0] -
            self._seq.data[self.curFrame].dpt.shape[0] // 4,
            self.curData[self.lastind, 0] +
            self._seq.data[self.curFrame].dpt.shape[0] // 4
        ])
        self.ax_xz.set_ylim([
            self.curData[self.lastind, 2] - self._seq.config['cube'][2] // 4,
            self.curData[self.lastind, 2] + self._seq.config['cube'][2] // 4
        ])
        self.ax_xz.set_xlabel('x')
        self.ax_xz.set_ylabel('z')

        self.ax_yz.cla()
        yz = dm[:, int(numpy.rint(self.curData[self.lastind, 0]))]
        self.ax_yz.plot(numpy.arange(dm.shape[0]), yz)
        self.plots_yz = []
        d, = self.ax_yz.plot(self.curData[self.lastind, 1],
                             self.curData[self.lastind, 2],
                             c='r',
                             marker='o',
                             markersize=8)
        self.plots_yz.append(d)
        self.ax_yz.set_xlim([
            self.curData[self.lastind, 1] -
            self._seq.data[self.curFrame].dpt.shape[1] // 4,
            self.curData[self.lastind, 1] +
            self._seq.data[self.curFrame].dpt.shape[1] // 4
        ])
        self.ax_yz.set_ylim([
            self.curData[self.lastind, 2] - self._seq.config['cube'][2] // 4,
            self.curData[self.lastind, 2] + self._seq.config['cube'][2] // 4
        ])
        self.ax_yz.set_xlabel('y')
        self.ax_yz.set_ylabel('z')

        self.update()

    def getCurrentStatus(self, filename_detections):
        pbar = pb.ProgressBar(
            maxval=len(self._seq.data),
            widgets=['Loading last status',
                     pb.Percentage(),
                     pb.Bar()])
        pbar.start()
        cache_str = ''
        with open(filename_detections, "r") as inputfile:
            cache_str = inputfile.readlines()

        for i in xrange(len(self._seq.data)):
            pbar.update(i)
            if len(self.subset_idxs) > 0:
                if i not in self.subset_idxs:
                    break

            hd = HandDetector(numpy.zeros((1, 1)), 0., 0.)  # dummy object
            com = numpy.asarray(
                hd.detectFromCache(filename_detections,
                                   self._seq.data[i].fileName, cache_str))
            if numpy.allclose(com[2], 0.):
                self.curFrame = i
                break
            else:
                self._seq.data[i] = self._seq.data[i]._replace(
                    com=self.importer.jointImgTo3D(com.reshape((3, ))))

        # redo last pose, it might be set to default and saved
        if self.curFrame > 0:
            if len(self.subset_idxs) > 0:
                if self.subset_idxs.index(self.curFrame) - 1 >= 0:
                    self.curFrame = self.subset_idxs[
                        self.subset_idxs.index(self.curFrame) - 1]
            else:
                self.curFrame -= 1

    def saveCurrent(self):

        self._seq.data[self.curFrame] = self._seq.data[self.curFrame]._replace(
            com=self.importer.jointImgTo3D(self.curData.reshape((3, ))))

        if self.filename_det is not None:
            self.importer.saveSequenceDetections(self._seq, self.filename_det)

        # save log file
        if self.file_log is not None:
            self.file_log.write('{}, {}, {}@{}, {}\n'.format(
                self._seq.data[self.curFrame].fileName,
                time.strftime("%d.%m.%Y %H:%M:%S +0000", time.gmtime()),
                getpass.getuser(),
                os.uname()[1],
                time.time() - self.start_time))
            self.file_log.flush()

    def connectEvents(self):
        self.canvas_xy.mpl_connect('button_press_event',
                                   self.button_press_callback)
        self.canvas_xy.mpl_connect('button_release_event',
                                   self.button_release_callback)
        self.canvas_xy.mpl_connect('motion_notify_event',
                                   self.motion_notify_callback)

    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"

        path = unicode(
            QFileDialog.getSaveFileName(self, 'Save file', '', file_choices))
        if path:
            self.canvas_xy.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)

    def pointcloudButton_callback(self):
        self.pointcloud()

    def nextButton_callback(self):
        self.next()

    def prevButton_callback(self):
        self.prev()

    def keyPressEvent(self, event):
        if self.lastind is None:
            return

        if event.text() == 'q':
            QApplication.instance().quit()
        elif event.text() == 'p':
            # previous
            self.prev()
            print 'prev'
        elif event.text() == 'n':
            # next
            self.next()
            print 'next'
        elif event.text() == '3':
            # pointcloud
            self.pointcloud()
            print '3D'
        elif event.text() == 'r':
            # reload
            self.panned = False
            self.showCurrent()
            print 'reload'
        elif event.text() == 's':
            # save
            if self.filename_det is not None:
                self.importer.saveSequenceDetections(self._seq,
                                                     self.filename_det)
            print 'saved'
        elif event.text() == 'a':
            # snap to z
            if self.lastind is not None:
                self.snap_z(self.lastind)
                print 'align'
                self.showContext()
        elif event.text() == 'z':
            # snap to z
            self.snap_z()
            print 'snap'
            self.showContext()
        elif event.key() == Qt.Key_Plus:
            self.curData[self.lastind, 2] += 5.
            print "z+=5"
            self.showContext()
        elif event.key() == Qt.Key_Minus:
            self.curData[self.lastind, 2] -= 5.
            print "z-=5"
            self.showContext()
        elif event.key() == Qt.Key_Up:
            self.curData[self.lastind, 1] -= 1.
            print "x-=1"
            self.showCurrent()
        elif event.key() == Qt.Key_Down:
            self.curData[self.lastind, 1] += 1.
            print "x+=1"
            self.showCurrent()
        elif event.key() == Qt.Key_Right:
            self.curData[self.lastind, 0] += 1.
            print "y+=1"
            self.showCurrent()
        elif event.key() == Qt.Key_Left:
            self.curData[self.lastind, 0] -= 1.
            print "y-=1"
            self.showCurrent()
        else:
            return

        self.update()

    def snap_z(self, idx=None):
        dm = self.importer.loadDepthMap(self.path_prefix +
                                        self._seq.data[self.curFrame].fileName)
        if idx is None:
            for i in range(self.curData.shape[0]):
                self.curData[i, 2] = dm[int(numpy.rint(self.curData[i, 1])),
                                        int(numpy.rint(self.curData[i, 0]))]
        else:
            self.curData[idx, 2] = dm[int(numpy.rint(self.curData[idx, 1])),
                                      int(numpy.rint(self.curData[idx, 0]))]

    def pointcloud(self):
        dm = self.importer.loadDepthMap(self.path_prefix +
                                        self._seq.data[self.curFrame].fileName)
        cur3D = self.importer.jointImgTo3D(self.curData[0]).reshape((1, 3))
        hd = HandDetector(dm,
                          self.importer.fx,
                          self.importer.fy,
                          importer=self.importer)
        dpt, M, com = hd.cropArea3D(self.curData[0].reshape((3, )),
                                    size=self._seq.config['cube'],
                                    docom=False)
        self.hpe.plotResult3D(dpt,
                              M,
                              cur3D,
                              cur3D,
                              showGT=False,
                              niceColors=False)

    def next(self):
        self.panned = False
        self.saveCurrent()
        if len(self.subset_idxs) > 0:
            if len(self.subset_idxs) > self.subset_idxs.index(
                    self.curFrame) + 1:
                self.curFrame = self.subset_idxs[
                    self.subset_idxs.index(self.curFrame) + 1]
            else:
                print "Done"
                QApplication.instance().quit()
        else:
            if self.curFrame < len(self._seq.data) - 1:
                self.curFrame += 1
            else:
                print "Done"
                QApplication.instance().quit()

        # reset timer
        self.start_time = time.time()

        # if there is no data, use the previous data to initialize
        com = self._seq.data[self.curFrame].com
        if numpy.allclose(com, 0.):
            prevFrame = self.curFrame
            if len(self.subset_idxs) > 0:
                if self.subset_idxs.index(self.curFrame) - 1 >= 0:
                    prevFrame = self.subset_idxs[
                        self.subset_idxs.index(self.curFrame) - 1]
            else:
                if self.curFrame > 0:
                    prevFrame = self.curFrame - 1
            prev_com = self._seq.data[prevFrame].com
            if numpy.allclose(prev_com, 0.):
                self.curData = numpy.zeros((1, 3))
            else:
                self.curData = self.importer.joint3DToImg(prev_com).reshape(
                    (1, 3))
        else:
            self.curData = self.importer.joint3DToImg(com).reshape((1, 3))
        self.showCurrent()

    def prev(self):
        self.panned = False
        self.saveCurrent()
        if len(self.subset_idxs) > 0:
            if self.subset_idxs.index(self.curFrame) - 1 >= 0:
                self.curFrame = self.subset_idxs[
                    self.subset_idxs.index(self.curFrame) - 1]
            else:
                print "First already selected!"
        else:
            if self.curFrame > 0:
                self.curFrame -= 1
            else:
                print "First already selected!"

        # reset timer
        self.start_time = time.time()

        prev_com = self._seq.data[self.curFrame].com
        if numpy.allclose(prev_com, 0.):
            self.curData = numpy.zeros((1, 3))
        else:
            self.curData = self.importer.joint3DToImg(prev_com).reshape((1, 3))
        self.showCurrent()

    def update(self):
        if self.lastind is None:
            return

        self.selected.set_visible(True)
        if self._ind is not None:
            self.selected.set_data(self.curData[self._ind, 0],
                                   self.curData[self._ind, 1])

        self.text.set_text('joint: %d' % self.lastind)
        self.ax_xy.get_figure().canvas.draw()
        self.ax_xz.get_figure().canvas.draw()
        self.ax_yz.get_figure().canvas.draw()
        if self.ax_color:
            if self._ind is not None:
                j2D = self.importer.jointsDpt2DToCol2D(self.curData)
                self.plots_color[self._ind].set_data(j2D[self._ind, 0],
                                                     j2D[self._ind, 1])

            self.ax_color.get_figure().canvas.draw()

    def get_ind_under_point(self, event):
        """
        get the index of the vertex under point if within epsilon tolerance
        :param event: qt event
        :return: index of selected point
        """

        # display coords
        distances = numpy.hypot(event.xdata - self.curData[:, 0],
                                event.ydata - self.curData[:, 1])
        indmin = distances.argmin()

        if distances[indmin] >= self.epsilon:
            ind = None
        else:
            ind = indmin
        self.lastind = ind
        return ind

    def button_press_callback(self, event):
        """
        whenever a mouse button is pressed
        :param event: qt event
        :return:
        """
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        self._ind = self.get_ind_under_point(event)
        print "got joint id", self._ind

        # if there is only one joint
        if self._ind is None and self.curData.shape[0] == 1:
            self._ind = 0
            self.lastind = 0
            self.plots_xy[self._ind].set_data([event.xdata, event.ydata])

        if self._ind is not None:
            x0, y0 = self.plots_xy[self._ind].get_data()
            self.press = x0, y0, event.xdata, event.ydata
        self.update()

    def button_release_callback(self, event):
        """
        whenever a mouse button is released
        :param event: qt event
        :return:
        """
        if event.button != 1:
            return
        if self._ind is None:
            return
        x, y = self.plots_xy[self._ind].get_data()
        self.curData[self._ind, 0] = x
        self.curData[self._ind, 1] = y

        # set to closest valid depth if at invalid depth
        dm = self.importer.loadDepthMap(self.path_prefix +
                                        self._seq.data[self.curFrame].fileName)
        if numpy.isclose(dm[int(y), int(x)], self.importer.getDepthMapNV()):
            validmsk = ~numpy.isclose(dm, self.importer.getDepthMapNV())
            pts = numpy.asarray(numpy.where(validmsk)).transpose()
            deltas = pts - numpy.asarray([int(y), int(x)])
            dist = numpy.einsum('ij,ij->i', deltas, deltas)
            pos = numpy.argmin(dist)
            self.curData[self._ind,
                         2] = dm[pts[pos][0],
                                 pts[pos][1]] + 10  # add offset to depth
        else:
            self.curData[self._ind,
                         2] = dm[int(y), int(x)] + 10  # add offset to depth
        self._ind = None
        self.showCurrent()
        self.showContext()

    def motion_notify_callback(self, event):
        """
        on mouse movement
        :param event: qt event
        :return:
        """
        if self._ind is None:
            return
        if event.inaxes is None:
            return
        if event.button != 1:
            return
        x0, y0, xpress, ypress = self.press
        dx = event.xdata - xpress
        dy = event.ydata - ypress
        self.selected.set_data(x0 + dx, y0 + dy)
        self.plots_xy[self._ind].set_data(x0 + dx, y0 + dy)
        self.ax_xy.get_figure().canvas.draw()
예제 #31
0
파일: Core.py 프로젝트: arksega/Rheometro
class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.createGUI()

    def createGUI(self):
        """Crea y configura todos los elementos de la itefaz"""
        self.arduino = ReadArduino()

        if len(self.arduino.arduinos) < 1:
          mensaje = QMessageBox(self)
          mensaje.setText('No hay algun arduino para trabajar')
          mensaje.setWindowTitle('Hardware no disponible')
          mensaje.setIcon(QMessageBox.Critical)
          mensaje.exec_()
          exit()
        self.arduino.start()

        # Generacion de elementos principales de la grafica
        self.dpi = 100
        self.fig = Figure((6.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        #self.canvas.setParent(self.frame)

        # Configuracion de la grafica
        self.axes = self.fig.add_subplot(111)
        self.axes.set_axis_bgcolor('black')
        self.axes.grid(True, color='gray')

        # Declaracion de interfaz
        self.pause = QPushButton('Pausar')
        self.pause.setDisabled(True)
        self.pause.clicked.connect(self.doPause)

        self.comenzar = QPushButton('Comenzar')
        self.comenzar.setCheckable(True)
        self.comenzar.toggled.connect(self.togglePrueba)

        self.guardar = QPushButton('Guardar')
        self.guardar.clicked.connect(self.doGuardar)

        self.nombreL = QLabel('Nombre de la prueba')
        self.nombre = QLineEdit()

        self.tiempoPrueba = QSpinBox()
        self.tiempoPrueba.setMinimum(1)
        self.tiempoPrueba.setDisabled(True)

        self.grupoTiempo = QGroupBox('Manejo de tiempo')
        self.grupoSignal = QGroupBox(u'Señales')
        self.politicaTiempo = QButtonGroup()
        self.tiempoFijo = QRadioButton('Tiempo fijo')
        self.tiempoIlimitado = QRadioButton('Tiempo ilimitado')
        self.tiempoIlimitado.setChecked(True)
        self.tiempoIlimitado.toggled.connect(self.cambiaPolitica)

        self.led0 = QPushButton('0')
        self.led1 = QPushButton('1')
        self.led2 = QPushButton('2')
        self.led3 = QPushButton('3')
        self.led0.setCheckable(True)
        self.led1.setCheckable(True)
        self.led2.setCheckable(True)
        self.led3.setCheckable(True)
        self.led0.toggled.connect(self.arduino.led0)
        self.led1.toggled.connect(self.arduino.led1)
        self.led2.toggled.connect(self.arduino.led2)
        self.led3.toggled.connect(self.arduino.led3)

        # Configuracion de la interfaz
        gt = QGridLayout()
        gt.addWidget(self.tiempoIlimitado, 0, 0)
        gt.addWidget(self.tiempoFijo, 1, 0)
        gt.addWidget(self.tiempoPrueba, 1, 1)
        gt.addWidget(self.pause, 0, 2, 2, 1)
        self.grupoTiempo.setLayout(gt)

        gs = QGridLayout()
        gs.addWidget(self.led0, 2, 2)
        gs.addWidget(self.led1, 2, 3)
        gs.addWidget(self.led2, 3, 2)
        gs.addWidget(self.led3, 3, 3)
        self.grupoSignal.setLayout(gs)

        gp = QGridLayout()
        gp.addWidget(self.nombreL, 1, 0)
        gp.addWidget(self.nombre, 1, 1)
        gp.addWidget(self.comenzar, 1, 2)
        gp.addWidget(self.guardar, 1, 3)
        gp.addWidget(self.grupoTiempo, 2, 0, 1, 2)
        gp.addWidget(self.grupoSignal, 2, 2, 1, 2)
        gp.addWidget(self.canvas, 0, 0, 1, 4)

        self.frame = QWidget()
        self.frame.setLayout(gp)
        self.setCentralWidget(self.frame)

        self.data = []
        self.line = self.axes.plot(
            self.data,
            linewidth=1,
            color=(1, 1, 0),
            )[0]

        # Manejo de tiempo
        self.tiempoTrancurrido = 0
        self.contadorActializa = QTimer()
        self.contadorActializa.timeout.connect(self.refresh)
        self.lecturasXSegundo = 20
        self.contadorActializa.setInterval(1000 / self.lecturasXSegundo)

        self.contadorPrincipal = QTimer()
        self.contadorPrincipal.timeout.connect(self.comenzar.toggle)

        self.draw_chart()

    def detenerPrueba(self):
        self.contadorActializa.stop()
        self.contadorPrincipal.stop()
        self.comenzar.setText('Comenzar')
        self.pause.setText('Pausar')
        self.pause.setDisabled(True)

    def comenzarPrueba(self):
        self.data = []
        self.tiempoTrancurrido = 0
        self.draw_chart()
        if self.tiempoFijo.isChecked():
            self.contadorPrincipal.setInterval(
                self.tiempoPrueba.value() * 1000)
        else:
            self.contadorPrincipal.setInterval(525600000)  # Un año
        self.contadorActializa.start()
        self.contadorPrincipal.start()
        self.comenzar.setText('Detener')
        self.pause.setDisabled(False)

    def togglePrueba(self):
        """Metodo para comenzar y detener la prueba actual"""
        if self.comenzar.isChecked():
            self.comenzarPrueba()
        else:
            self.detenerPrueba()

    def cambiaPolitica(self):
        """Habilita la interfaz para manejo manual del tiempo"""
        if self.tiempoIlimitado.isChecked():
            self.tiempoPrueba.setDisabled(True)
        else:
            self.tiempoPrueba.setEnabled(True)

    def doGuardar(self):
        """Verifica la existencia de datos y los guarda en png, cvs y pdf"""
        if self.nombre.text() == '':
            mensaje = QMessageBox(self)
            mensaje.setText('Ingrese un nombre para la prueba')
            mensaje.setWindowTitle('Error al guardar')
            mensaje.setIcon(QMessageBox.Critical)
            mensaje.exec_()
        elif len(self.data) == 0:
            mensaje = QMessageBox(self)
            mensaje.setText('No hay datos para guardar')
            mensaje.setWindowTitle('Error al guardar')
            mensaje.setIcon(QMessageBox.Critical)
            mensaje.exec_()
        else:
            nombre = str(self.nombre.text().toUtf8())
            archivo = open(nombre + '.csv', 'w')
            archivo.write(str(self.data)[1:-1] + '\n')
            archivo.close()

            pdf = PdfPages(nombre + '.pdf')
            self.fig.savefig(pdf, format='pdf')
            pdf.close()

            self.canvas.print_figure(nombre + '.png', dpi=self.dpi)

            mensaje = QMessageBox(self)
            mensaje.setText('La prueba a sido guardada correctamente')
            mensaje.setWindowTitle('Guardado con exito')
            mensaje.setIcon(QMessageBox.Information)
            mensaje.exec_()

    def doPause(self):
        """Maneja las pausas de la aplicación"""
        if self.contadorActializa.isActive():
            self.contadorActializa.stop()
            self.contadorPrincipal.stop()
            self.pause.setText('Reanudar')
        else:
            self.contadorActializa.start()
            # Recalcula el tiempo restante de la prueba
            self.contadorPrincipal.setInterval(
                self.tiempoPrueba.value() * 1000 - self.tiempoTrancurrido)
            self.contadorPrincipal.start()
            self.pause.setText('Pausar')

    def refresh(self):
        """Agrega un dato al conjunto y regenera la gráfica"""
        self.tiempoTrancurrido += 1000 / self.lecturasXSegundo
        self.data.append(int(self.arduino.data))
        self.draw_chart()

    def draw_chart(self):
        """Regenera la grafica"""
        count = round(len(self.data) * 1.0 / self.lecturasXSegundo, 3)
        xmax = count if count > 3 else 3
        xmin = 0

        self.axes.set_xbound(lower=xmin, upper=xmax)
        self.axes.set_ybound(lower=0, upper=1023)

        self.line.set_xdata(np.arange(0, count, 1.0 / self.lecturasXSegundo))
        self.line.set_ydata(np.array(self.data))

        self.canvas.draw()

    def closeEvent(self, event):
        self.arduino.stop()
class StatisticsWindow(QWidget):
    def __init__(self,parent=None):
        QWidget.__init__(self,parent)
        self.setWindowFlags(Qt.Window)
        self.setWindowTitle('Statistics:')
        self.parent=parent
        self.figure,self.axes = plt.subplots(2,1,sharex=True)
        self.figure.set_size_inches((5.0,4.0))
        self.canvas=FigureCanvas(self.figure)
        self.canvas.setParent(self)       
        layout = QVBoxLayout()
        layout.addWidget(self.canvas)
        #commented away as it causes segmentation faults in my ubuntu, even though
        #it works fine in my windows 7 computer.
        #self.mpl_toolbar = NavigationToolBar(self.canvas,self)         
        #layout.addWidget(self.mpl_toolbar)
        self.setLayout(layout)
        self.dataChanged()
        
    def draw(self):
        self.canvas.draw()
    
    def closeEvent(self,event):
        self.parent.closeStatWindow()
        self.close()
        
    def exportStats(self):
        dialog = QFileDialog(self, "Choose a filename and type to save to, suffix declares type","./stats.csv")
        filetypes = self.canvas.get_supported_filetypes_grouped().items()
        filetypes.append(('Spreadsheet',['csv']))
        filetypes.sort()
        default_filetype = 'csv'
        filters = []
        selectedFilter = None
        for name, exts in filetypes:
            exts_list = " ".join(['*.%s' % ext for ext in exts])
            filter = '%s (%s)' % (name, exts_list)
            if default_filetype in exts:
                selectedFilter = filter
            filters.append(filter)
        filters = ';;'.join(filters)
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.setNameFilter(filters)
        dialog.selectNameFilter(selectedFilter)
        dialog.setViewMode(QFileDialog.Detail)
        dialog.setAcceptMode(QFileDialog.AcceptSave)

        if not dialog.exec_():
            return
        fname = dialog.selectedFiles()
        if not fname[0]:
            return
        fname=fname[0]
        if not '.' in fname:
            fname+='.csv'
        self.dataChanged()
        if '.csv' in fname:
            with open(fname, 'wb') as f:
                w = csv.writer(f, delimiter=';', quoting=csv.QUOTE_NONE)
                w.writerow(["Total Eaten:", "Total Walked:"])
                for i in range(len(self.parent.statEaten)):
                    w.writerow([self.parent.statEaten[i],
                                self.parent.statWalked[i]])
        else:
            try:
                self.canvas.print_figure( unicode(fname) )
            except Exception, e:
                QMessageBox.critical(
                    self, "Error saving file", str(e),
                    QMessageBox.Ok, QMessageBox.NoButton)   
예제 #33
0
class AppForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('Channelizer 2')
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        self.dacStatus = 'off'
        self.dramStatus = 'off'
        self.tapStatus = 'off'
        self.socketStatus = 'off'
        self.numFreqs=0
        self.ch_all = []
        self.attens = numpy.array([1. for i in range(256)])
        self.freqRes = 7812.5
        self.sampleRate = 512e6
        self.zeroChannels = [0]*256
        #writing threshold to register
        self.thresholds, self.medians = numpy.array([0.]*256), numpy.array([0.]*256)
        self.customThresholds = numpy.array([360.]*256)
        self.customResonators=numpy.array([[0.0,-1]]*256)   #customResonator[ch]=[freq,atten]
        
    def openClient(self):
        self.roach = corr.katcp_wrapper.FpgaClient(self.textbox_roachIP.text(),7147)
        time.sleep(2)
        self.status_text.setText('connection established')
        print 'Connected to ',self.textbox_roachIP.text()
        self.button_openClient.setDisabled(True)

    def loadFIRcoeffs(self):
        N_freqs = len(map(float, unicode(self.textedit_DACfreqs.toPlainText()).split()))
        taps = 26
        
        for ch in range(N_freqs):
            # If the resonator's attenuation is >=99 then its FIR should be zeroed
            if self.zeroChannels[ch]:
                lpf = numpy.array([0.]*taps)*(2**11-1)
                print 'deleted ch ',ch
            else:
                lpf = numpy.array(self.fir)*(2**11-1)
                print ch
                #lpf = numpy.array([1.]+[0]*(taps-1))*(2**11-1)
        #    26 tap, 25 us matched fir
                #lpf = numpy.array([0.0875788844768 , 0.0840583257978 , 0.0810527406206 , 0.0779008825067 , 0.075106964962 , 0.0721712998256 , 0.0689723729398 , 0.066450095496 , 0.0638302570705 , 0.0613005685486 , 0.0589247737004 , 0.0565981917436 , 0.0544878914297 , 0.0524710948658 , 0.0503447054014 , 0.0483170854189 , 0.0463121066637 , 0.044504238059 , 0.0428469827102 , 0.0410615366471 , 0.0395570640218 , 0.0380071830756 , 0.0364836787854 , 0.034960959124 , 0.033456372241 , 0.0321854467182])*(2**11-1)
                #26 tap, 20 us matched fir
                #lpf = numpy.array([ 0.102806030245 , 0.097570344415 , 0.0928789946181 , 0.0885800360545 , 0.0841898850361 , 0.079995145104 , 0.0761649967857 , 0.0724892663141 , 0.0689470889358 , 0.0657584886557 , 0.0627766233242 , 0.0595952531565 , 0.0566356208278 , 0.053835736579 , 0.0510331408751 , 0.048623806127 , 0.0461240096904 , 0.0438134132285 , 0.0418265743203 , 0.0397546477453 , 0.0377809254888 , 0.0358044897245 , 0.0338686929847 , 0.0321034547839 , 0.0306255734188 , 0.0291036235859 ])*(2**11-1)
                #26 tap, 30 us matched fir
                #lpf = numpy.array([ 0.0781747107378 , 0.0757060398243 , 0.0732917718492 , 0.0708317694778 , 0.0686092845217 , 0.0665286923521 , 0.0643467681477 , 0.0621985982971 , 0.0600681642401 , 0.058054873199 , 0.0562486467178 , 0.0542955553149 , 0.0527148880657 , 0.05096365681 , 0.0491121116212 , 0.0474936094733 , 0.0458638771941 , 0.0443219286645 , 0.0429290438102 , 0.0415003391096 , 0.0401174498302 , 0.0386957715665 , 0.0374064708747 , 0.0362454802408 , 0.0350170176804 , 0.033873302383 ])*(2**11-1)
                #lpf = lpf[::-1]
                #    26 tap, lpf, 250 kHz,
                #lpf = numpy.array([-0 , 0.000166959420533 , 0.00173811663844 , 0.00420937801998 , 0.00333739357391 , -0.0056305703275 , -0.0212738104942 , -0.0318529375832 , -0.0193635986879 , 0.0285916612022 , 0.106763943766 , 0.18981814328 , 0.243495321192 , 0.243495321192 , 0.18981814328 , 0.106763943766 , 0.0285916612022 , -0.0193635986879 , -0.0318529375832 , -0.0212738104942 , -0.0056305703275 , 0.00333739357391 , 0.00420937801998 , 0.00173811663844 , 0.000166959420533 , -0])*(2**11-1)
                #    26 tap, lpf, 125 kHz.
                #lpf = numpy.array([0 , -0.000431898216436 , -0.00157886921107 , -0.00255492263971 , -0.00171727439076 , 0.00289724121972 , 0.0129123447233 , 0.0289345497995 , 0.0500906370566 , 0.0739622085341 , 0.0969821586979 , 0.115211955161 , 0.125291869266 , 0.125291869266 , 0.115211955161 , 0.0969821586979 , 0.0739622085341 , 0.0500906370566 , 0.0289345497995 , 0.0129123447233 , 0.00289724121972 , -0.00171727439076 , -0.00255492263971 , -0.00157886921107 , -0.000431898216436 , -0])*(2**11-1)
                #    Generic 40 tap matched filter for 25 us lifetime pulse
                #lpf = numpy.array([0.153725595011 , 0.141052390733 , 0.129753816201 , 0.119528429291 , 0.110045314901 , 0.101336838027 , 0.0933265803805 , 0.0862038188673 , 0.0794067694409 , 0.0729543134914 , 0.0674101836798 , 0.0618283869464 , 0.0567253144676 , 0.0519730940444 , 0.047978953698 , 0.043791412767 , 0.0404560656757 , 0.0372466775252 , 0.0345000956808 , 0.0319243455811 , 0.0293425115323 , 0.0268372778298 , 0.0245216835234 , 0.0226817116475 , 0.0208024488535 , 0.0189575043357 , 0.0174290665862 , 0.0158791788119 , 0.0144611054123 , 0.0132599563305 , 0.0121083419203 , 0.0109003580368 , 0.0100328742978 , 0.00939328253743 , 0.00842247241585 , 0.00789304712484 , 0.00725494259117 , 0.00664528407122 , 0.00606688645845 , 0.00552041438208])*(2**11-1)                
                #lpf = lpf[::-1]

            for n in range(taps/2):
                coeff0 = int(lpf[2*n])
                coeff1 = int(lpf[2*n+1])
                coeff0 = numpy.binary_repr(int(lpf[2*n]), 12)
                coeff1 = numpy.binary_repr(int(lpf[2*n+1]), 12)
                coeffs = int(coeff1+coeff0, 2)
                coeffs_bin = struct.pack('>l', coeffs)
                register_name = 'FIR_b' + str(2*n) + 'b' + str(2*n+1)
                self.roach.write(register_name, coeffs_bin)
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (1<<0))
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (0<<0))
        
        # Inactive channels will also be zeroed.
        lpf = numpy.array([0.]*taps)
        for ch in range(N_freqs, 256):
            for n in range(taps/2):
                #coeffs = struct.pack('>h', lpf[2*n]) + struct.pack('>h', lpf[2*n+1])
                coeffs = struct.pack('>h', lpf[2*n+1]) + struct.pack('>h', lpf[2*n])
                register_name = 'FIR_b' + str(2*n) + 'b' + str(2*n+1)
                self.roach.write(register_name, coeffs)
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (1<<0))
                self.roach.write_int('FIR_load_coeff', (ch<<1) + (0<<0))
                
        print 'done loading fir.'
        self.status_text.setText('FIRs loaded')
     
    def find_nearest(self, array, value):
        idx=(numpy.abs(array-value)).argmin()
        return idx

    def loadCustomThresholds(self):
        freqFile =str(self.textbox_freqFile.text())
        if freqFile[-8:] == '_NEW.txt':
            freqFile=freqFile[:-8]+'_THRESHOLD.txt'
        else:
            freqFile=freqFile[:-4]+'_THRESHOLD.txt'
        try:
            x=numpy.loadtxt(freqFile)
            self.customThresholds = numpy.array([360.]*256)
            if type(x[0]) == numpy.ndarray:
                for arr in x:
                    self.customThresholds[int(arr[0])]=arr[1]
            else:
                self.customThresholds[int(x[0])]=x[1]
            print 'Custom Thresholds loaded from',freqFile
        except IOError:
            #No custom thresholds to load
            pass


    def rmCustomThreshold(self):
        ch = int(self.textbox_channel.text())
        if self.customThresholds[ch] != 360.0:
            self.customThresholds[ch]=360.0
            print "Custom Threshold from channel",ch,"removed."
            #self.loadSingleThreshold(ch)
            scale_to_angle = 360./2**16*4/numpy.pi
            self.roach.write_int('capture_threshold', int(self.thresholds[ch]/scale_to_angle))
            self.roach.write_int('capture_load_thresh', (ch<<1)+(1<<0))
            self.roach.write_int('capture_load_thresh', (ch<<1)+(0<<0))
            print "Old threshold updated to roach"

            freqFile =str(self.textbox_freqFile.text())
            if freqFile[-8:] == '_NEW.txt':
                freqFile=freqFile[:-8]+'_THRESHOLD.txt'
            else:
                freqFile=freqFile[:-4]+'_THRESHOLD.txt'
            try:
                x=numpy.loadtxt(freqFile)
                f=open(freqFile,'w')
                if type(x[0]) == numpy.ndarray:
                    for arr in x:
                        #print 'arr',arr
                        if arr[0]!=ch:
                            f.write(str(int(arr[0]))+'\t'+str(float(arr[1]))+'\n')
                else:
                    if x[0]!=ch:
                        f.write(str(int(x[0]))+'\t'+str(float(x[1]))+'\n')
                print "Removed Custom Threshold on channel ",ch," from ",freqFile
                self.status_text.setText("Removed Custom Threshold on channel "+str(ch)+" from "+str(freqFile))
                f.close()
            except IOError:
                print 'Unable to remove custom threshold from channel',ch
        else:
            print "No custom threshold set for channel",ch


    def setCustomThreshold(self,event):
        scale_to_angle = 360./2**16*4/numpy.pi
        ch = int(self.textbox_channel.text())
        newThreshold = event.ydata
        #print "Threshold selected:",newThreshold
        if event.ydata != None and self.mpl_toolbar.mode == '':
            self.loadSingleThreshold(ch)                #resets median
            newThreshold = newThreshold - self.medians[ch]      #for threshold adjusting firmware only!
            self.customThresholds[ch] = newThreshold
            newThreshold = int(newThreshold/scale_to_angle)
            #print "writing threshold to register:",newThreshold
            #print "median for channel ",ch,": ",self.medians[ch]
            #self.customThresholds[ch] = newThreshold
        
            #print "new threshold: ",newThreshold
            #print "old threshold: ",self.thresholds[ch]/scale_to_angle
        
            self.roach.write_int('capture_threshold', newThreshold)
            self.roach.write_int('capture_load_thresh', (ch<<1)+(1<<0))
            self.roach.write_int('capture_load_thresh', (ch<<1)+(0<<0))
            print "channel: ", ch, "median: ", self.medians[ch], "new threshold: ", scale_to_angle*newThreshold
            #print self.customThresholds[ch]
            #self.loadSingleThreshold(ch)

            freqFile =str(self.textbox_freqFile.text())
            if freqFile[-8:] == '_NEW.txt':
                freqFile=freqFile[:-8]+'_THRESHOLD.txt'
            else:
                freqFile=freqFile[:-4]+'_THRESHOLD.txt'
            try:
                f=open(freqFile,'a')
                f.write(str(int(ch))+'\t'+str(float(self.customThresholds[ch]))+'\n')
                f.close()
                print 'Saved custom threshold to',freqFile
            except IOError:
                print 'ERROR: There was a problem saving thresholds to',freqFile

    def loadThresholds(self):
        """    Takes two time streams and concatenates together for a longer sample.
                median is used instead of mean.
                """
        x = raw_input('Is the lamp off? ')
        Nsigma = float(self.textbox_Nsigma.text())
        N_freqs = len(map(float, unicode(self.textedit_DACfreqs.toPlainText()).split()))
        self.thresholds, self.medians = numpy.array([0.]*N_freqs), numpy.array([0.]*N_freqs)

        #for ch in range(N_freqs):
            #print 'attempting to load channel: ',ch
        #    self.loadSingleThreshold(ch)

        steps = int(self.textbox_timeLengths.text())
        L = 2**10
        scale_to_angle = 360./2**16*4/numpy.pi
        for ch in range(N_freqs):
            bin_data_phase = ''
            for n in range(steps):
                self.roach.write_int('ch_we', ch)
                self.roach.write_int('startSnap', 0)
                self.roach.write_int('snapPhase_ctrl', 1)
                self.roach.write_int('snapPhase_ctrl', 0)
                self.roach.write_int('startSnap', 1)
                time.sleep(0.001)
                bin_data_phase = bin_data_phase + self.roach.read('snapPhase_bram', 4*L)    
            
            phase = []
            for m in range(steps*L):
                phase.append(struct.unpack('>h', bin_data_phase[m*4+2:m*4+4])[0])
                phase.append(struct.unpack('>h', bin_data_phase[m*4+0:m*4+2])[0])
            phase = numpy.array(phase)
            #phase_avg = numpy.median(phase)
            #sigma = phase.std()

            n,bins= numpy.histogram(phase,bins=100)
            n = numpy.array(n,dtype='float32')/numpy.sum(n)
            tot = numpy.zeros(len(bins))
            for i in xrange(len(bins)):
                tot[i] = numpy.sum(n[:i])
            bins1 = .5*(bins[1:]+bins[:-1])
            med = bins[self.find_nearest(tot,0.5)]
            thresh = bins[self.find_nearest(tot,0.05)]
            #threshold = int(med-Nsigma*abs(med-thresh))
            threshold = int(-Nsigma*abs(med-thresh))    #for threshold adjusting firmware!
            
            
            #threshold = int((phase_avg - Nsigma*sigma))
            # -25736 = -180 degrees
            if threshold < -25736:
                threshold = -25736
            self.thresholds[ch] = scale_to_angle*threshold
            self.medians[ch] = scale_to_angle*med

            if self.customThresholds[ch] != 360.0:
                threshold = self.customThresholds[ch]/scale_to_angle
                if threshold < -25736:
                    threshold = -25736
                print 'Channel '+str(ch)+' has a custom threshold'

            self.roach.write_int('capture_threshold', threshold)
            self.roach.write_int('capture_load_thresh', (ch<<1)+(1<<0))
            self.roach.write_int('capture_load_thresh', (ch<<1)+(0<<0))
            print "channel: ", ch, "median: ", scale_to_angle*med, "threshold: ", scale_to_angle*threshold
            #print "channel: ", ch, "avg: ", scale_to_angle*phase_avg, "sigma: ", scale_to_angle*sigma, "threshold: ", scale_to_angle*threshold
        
        self.status_text.setText('Thresholds loaded')
        print 'Done loading thresholds'

    def loadSingleThreshold(self,ch):
        #print 'ch: ',ch
        L = 2**10
        scale_to_angle = 360./2**16*4/numpy.pi
        Nsigma = float(self.textbox_Nsigma.text())
        bin_data_phase = ''
        steps = int(self.textbox_timeLengths.text())
        for n in range(steps):
            self.roach.write_int('ch_we', ch)
            self.roach.write_int('startSnap', 0)
            self.roach.write_int('snapPhase_ctrl', 1)
            self.roach.write_int('snapPhase_ctrl', 0)
            self.roach.write_int('startSnap', 1)
            time.sleep(0.001)
            bin_data_phase = bin_data_phase + self.roach.read('snapPhase_bram', 4*L)    
            
        phase = []
        for m in range(steps*L):
            phase.append(struct.unpack('>h', bin_data_phase[m*4+2:m*4+4])[0])
            phase.append(struct.unpack('>h', bin_data_phase[m*4+0:m*4+2])[0])
        phase = numpy.array(phase)
        #phase_avg = numpy.median(phase)
        #sigma = phase.std()

        n,bins= numpy.histogram(phase,bins=100)
        n = numpy.array(n,dtype='float32')/numpy.sum(n)
        tot = numpy.zeros(len(bins))
        for i in xrange(len(bins)):
            tot[i] = numpy.sum(n[:i])
        bins1 = .5*(bins[1:]+bins[:-1])
        med = bins[self.find_nearest(tot,0.5)]
        thresh = bins[self.find_nearest(tot,0.05)]
        #threshold = int(med-Nsigma*abs(med-thresh))
        threshold = int(-Nsigma*abs(med-thresh))    #for threshold adjusting firmware!
            
            
        #threshold = int((phase_avg - Nsigma*sigma))
        # -25736 = -180 degrees
        if threshold < -25736:
            threshold = -25736
        self.thresholds[ch] = scale_to_angle*threshold
        self.medians[ch] = scale_to_angle*med

        if self.customThresholds[ch] != 360.0:
            threshold = self.customThresholds[ch]/scale_to_angle
            if threshold < -25736:
                threshold = -25736
            print 'Channel '+str(ch)+' has a custom threshold'

        self.roach.write_int('capture_threshold', threshold)
        self.roach.write_int('capture_load_thresh', (ch<<1)+(1<<0))
        self.roach.write_int('capture_load_thresh', (ch<<1)+(0<<0))
        print "channel: ", ch, "median: ", scale_to_angle*med, "threshold: ", scale_to_angle*threshold
        #print "channel: ", ch, "avg: ", scale_to_angle*phase_avg, "sigma: ", scale_to_angle*sigma, "threshold: ", scale_to_angle*threshold
        
    def snapshot(self):       
        self.displayResonatorProperties()
        ch_we = int(self.textbox_channel.text())
        self.roach.write_int('ch_we', ch_we)
        #print self.roach.read_int('ch_we')
        steps = int(self.textbox_snapSteps.text())
        L = 2**10
        bin_data_phase = ''
        for n in range(steps):
            self.roach.write_int('startSnap', 0)
            self.roach.write_int('snapPhase_ctrl', 1)
            self.roach.write_int('snapPhase_ctrl', 0)
            self.roach.write_int('startSnap', 1)
            time.sleep(0.001)
            bin_data_phase = bin_data_phase + self.roach.read('snapPhase_bram', 4*L)    
            
        phase = []
        for m in range(steps*L):
            phase.append(struct.unpack('>h', bin_data_phase[m*4+2:m*4+4])[0])
            phase.append(struct.unpack('>h', bin_data_phase[m*4+0:m*4+2])[0])
        phase = numpy.array(phase)*360./2**16*4/numpy.pi

        self.axes1.clear()
        #self.axes1.plot(phase, '.-', [self.thresholds[ch_we]]*2*L*steps, 'r.', [self.medians[ch_we]]*2*L*steps, 'g.')
        saveDir = str('')
        if saveDir != '':
            phasefilename = saveDir + 'snapshot_'+time.strftime("%Y%m%d-%H%M%S",time.localtime()) + str(self.textbox_roachIP.text())+'.txt'
            numpy.savetxt(phasefilename,phase,fmt='%.8e')

        if steps <= 1000:
            self.axes1.plot(phase,'.-')

        med=numpy.median(phase)

        print 'ch:',ch_we,'median:',med,
        thresh=self.thresholds[ch_we]

        if self.customThresholds[ch_we] != 360.0:
            thresh=self.customThresholds[ch_we]
            print "Custom Threshold: ", thresh,

        self.axes1.plot([thresh+med]*2*L*steps,'r.',[med]*2*L*steps,'g.',alpha=1)

        med=self.medians[ch_we]
        self.axes1.plot([thresh+med]*2*L*steps,'y.',[med]*2*L*steps,'y.',alpha=0.2)
        print "Threshold: ",self.thresholds[ch_we]

        #print "Channel: ",ch_we," median: " ,self.medians[ch_we], 
        #if self.customThresholds[ch_we] != 360.0:
        #    self.axes1.plot(phase, '.-', [self.customThresholds[ch_we]+self.medians[ch_we]]*2*L*steps, 'r.', [self.medians[ch_we]]*2*L*steps, 'g.',alpha=0.3)
        #    print "Custom Threshold: ",self.customThresholds[ch_we]," Threshold: ",self.thresholds[ch_we]
        #else:
        #   self.axes1.plot(phase, '.-', [self.thresholds[ch_we]+self.medians[ch_we]]*2*L*steps, 'r.', [self.medians[ch_we]]*2*L*steps, 'g.',alpha=0)
        #   print "Threshold: ",self.thresholds[ch_we]
        #print " "

        self.canvas.draw()
        print "snapshot taken"

    def longsnapshot(self):        
        self.displayResonatorProperties()
        ch_we = int(self.textbox_channel.text())
        self.roach.write_int('ch_we', ch_we)
        #print self.roach.read_int('ch_we')
        
        steps = int(self.textbox_longsnapSteps.text())
        L = 2**10
        numQDRSamples=2**19
        numBytesPerSample=4
        nLongsnapSamples = numQDRSamples*2*steps # 2 16-bit samples per 32-bit QDR word
        bin_data_phase = ''
        qdr_data_str = ''
        for n in range(steps):
            self.roach.write_int('snapPhase_ctrl', 0)
            self.roach.write_int('snapqdr_ctrl',0)
            self.roach.write_int('startSnap', 0)
            self.roach.write_int('snapqdr_ctrl',1)
            self.roach.write_int('snapPhase_ctrl', 1)
            self.roach.write_int('startSnap', 1)
            time.sleep(2)
            bin_data_phase = bin_data_phase + self.roach.read('snapPhase_bram', 4*L)    
            qdr_data_str = qdr_data_str + self.roach.read('qdr0_memory',numQDRSamples*numBytesPerSample)
            
        self.roach.write_int('snapPhase_ctrl', 0)
        self.roach.write_int('snapqdr_ctrl',0)
        self.roach.write_int('startSnap', 0)
        phase = []
        for m in range(steps*L):
            phase.append(struct.unpack('>h', bin_data_phase[m*4+2:m*4+4])[0])
            phase.append(struct.unpack('>h', bin_data_phase[m*4+0:m*4+2])[0])
        qdr_values = struct.unpack('>%dh'%(nLongsnapSamples),qdr_data_str)
        qdr_phase_values = numpy.array(qdr_values)*360./2**16*4/numpy.pi
        phase = numpy.array(phase)*360./2**16*4/numpy.pi
        fqdr = open('ch_out_%d.txt'%ch_we,'w')
        for q in qdr_phase_values:
            fqdr.write(str(q)+'\n')
        fsnap = open('ch_snap_%d.txt'%ch_we,'w')
        for q in phase:
            fsnap.write(str(q)+'\n')

        self.axes1.clear()
        #self.axes1.plot(phase, '.-', [self.thresholds[ch_we]]*2*L*steps, 'r.', [self.medians[ch_we]]*2*L*steps, 'g.')
        saveDir = str('')
        if saveDir != '':
            phasefilename = saveDir + 'snapshot_'+time.strftime("%Y%m%d-%H%M%S",time.localtime()) + str(self.textbox_roachIP.text())+'.txt'
            numpy.savetxt(phasefilename,phase,fmt='%.8e')


        med=numpy.median(phase)
        
        print 'ch:',ch_we,'median:',med,
        thresh=self.thresholds[ch_we]

        if self.customThresholds[ch_we] != 360.0:
            thresh=self.customThresholds[ch_we]
            print "Custom Threshold: ", thresh,

        if steps < 2:
            self.axes1.plot(qdr_phase_values,'b-')
            self.axes1.plot([thresh+med]*2*numQDRSamples*steps,'r-',[med]*2*numQDRSamples*steps,'g-',alpha=1)
            med=self.medians[ch_we]
            self.axes1.plot([thresh+med]*2*numQDRSamples*steps,'y-',[med]*2*numQDRSamples*steps,'y-',alpha=0.2)

            nFFTAverages = 100
            nSamplesPerFFT = nLongsnapSamples/nFFTAverages
            noiseFFT = numpy.zeros(nSamplesPerFFT)
            noiseFFTFreqs = numpy.fft.fftfreq(nSamplesPerFFT)
            for iAvg in xrange(nFFTAverages):
                noise = numpy.fft.fft(qdr_phase_values[iAvg*nSamplesPerFFT:(iAvg+1)*nSamplesPerFFT])
                noise = numpy.abs(noise)**2
                noiseFFT += noise
            noiseFFT /= nFFTAverages
            self.axes0.clear()
            nFFTfreqs = len(noiseFFTFreqs)/2
            noiseFFTFreqs *= 1e6 #convert MHz to Hz
            self.axes0.loglog(noiseFFTFreqs[1:nFFTfreqs],noiseFFT[1:nFFTfreqs])
            self.axes0.set_xlabel('Freq (Hz)')
            self.axes0.set_ylabel('FFT of snapshot, nAverages=%d'%nFFTAverages)


        print "Threshold: ",self.thresholds[ch_we]

        self.canvas.draw()
        print "longsnapshot taken"

    def readPulses(self):
        scale_to_degrees = 360./2**12*4/numpy.pi
        channel_count = [0]*256
        p1 = [[] for n in range(256)]
        timestamp = [[] for n in range(256)]
        baseline = [[] for n in range(256)]
        peaks = [[] for n in range(256)]
        seconds = int(self.textbox_seconds.text())
        steps = seconds*10
        self.roach.write_int('startBuffer', 1)
        time.sleep(1)
        for n in range(steps):
            addr0 = self.roach.read_int('pulses_addr')
            time.sleep(0.1)
            addr1 = self.roach.read_int('pulses_addr')
            bin_data_0 = self.roach.read('pulses_bram0', 4*2**14)
            bin_data_1 = self.roach.read('pulses_bram1', 4*2**14)

            if addr1 >= addr0:
                total_counts = addr1-addr0
                for n in range(addr0, addr1):
                    raw_data_1 = struct.unpack('>L', bin_data_1[n*4:n*4+4])[0]
                    raw_data_0 = struct.unpack('>L', bin_data_0[n*4:n*4+4])[0]
                    ch = raw_data_1/2**24
                    channel_count[ch] = channel_count[ch] + 1
                    timestamp[ch].append(raw_data_0%2**20)
                    baseline[ch].append((raw_data_0>>20)%2**12)
                    peaks[ch].append((raw_data_1>>12)%2**12)

            else:
                total_counts = addr1+2**14-addr0
                for n in range(addr0, 2**14):
                    raw_data_1 = struct.unpack('>L', bin_data_1[n*4:n*4+4])[0]
                    raw_data_0 = struct.unpack('>L', bin_data_0[n*4:n*4+4])[0]
                    ch = raw_data_1/2**24
                    channel_count[ch] = channel_count[ch] + 1
                    p1[ch].append((raw_data_1%2**12 - 2**11)*scale_to_degrees)
                    timestamp[ch].append(raw_data_0%2**20)
                    baseline[ch].append((raw_data_0>>20)%2**12)
                    peaks[ch].append((raw_data_1>>12)%2**12)
                for n in range(0, addr1):
                    raw_data_1 = struct.unpack('>L', bin_data_1[n*4:n*4+4])[0]
                    raw_data_0 = struct.unpack('>L', bin_data_0[n*4:n*4+4])[0]
                    ch = raw_data_1/2**24
                    channel_count[ch] = channel_count[ch] + 1
                    p1[ch].append((raw_data_1%2**12 - 2**11)*scale_to_degrees)
                    timestamp[ch].append(raw_data_0%2**20)
                    baseline[ch].append((raw_data_0>>20)%2**12)
                    peaks[ch].append((raw_data_1>>12)%2**12)
            print total_counts
        self.roach.write_int('startBuffer', 0)

        print 'sorted indices by counts', numpy.argsort(channel_count)[::-1]
        print 'sorted by counts', numpy.sort(channel_count)[::-1]
        print 'total counts by channel: ',channel_count
        channel_count = numpy.array(channel_count)
        ch = int(self.textbox_channel.text())
        numpy.savetxt('/home/sean/data/restest/test.dat', p1[ch])
        
        # With lamp off, run "readPulses."  If count rate is above 50, it's anamolous 
        # and it's FIR should be set to 0.
        #for n in range(256):
         #   if channel_count[n] > 100:
          #      self.zeroChannels[n] = 1   
        
        #x = numpy.arange(-270, 0, 3)
        #y = numpy.histogram(data, 90)
        base = numpy.array(baseline[ch],dtype='float')
        base = base/2.0**9-4.0
        base = base*180.0/numpy.pi
        peaksCh = numpy.array(peaks[ch],dtype = 'float')
        peaksCh = peaksCh/2.0**9-4.0
        peaksCh = peaksCh*180.0/numpy.pi
        peaksSubBase = peaksCh-base
        print 'count rate:',len(base)
        print 'mean baseline:',numpy.mean(base)
        print 'median baseline:',numpy.median(base) 
        print 'stddev baseline:',numpy.std(base)
        self.axes0.clear()
        #self.axes0.plot(timestamp[ch], '.')
        self.axes0.plot(base, 'g.-')
        self.axes0.plot(peaksCh, 'b.-')
        self.axes0.plot(peaksSubBase, 'r.-')
        self.canvas.draw()

    def channelInc(self):
        ch_we = int(self.textbox_channel.text())
        ch_we = ch_we + 1
        if ch_we >=self.numFreqs:
            ch_we=0
        self.textbox_channel.setText(str(ch_we))
        
    def toggleDAC(self):
        if self.dacStatus == 'off':
            print "Starting LUT...",
            self.roach.write_int('startDAC', 1)
            time.sleep(1)
            while self.roach.read_int('DRAM_LUT_rd_valid') != 0:
                self.roach.write_int('startDAC', 0)
                time.sleep(0.25)
                self.roach.write_int('startDAC', 1)
                time.sleep(1)
                print ".",
            print "done."
            #self.button_startDAC.setText('Stop DAC')
            self.dacStatus = 'on'
            self.status_text.setText('DAC turned on. ')       
        else:
            self.roach.write_int('startDAC', 0)
            #self.button_startDAC.setText('Start DAC')
            self.dacStatus = 'off'
        self.status_text.setText('DAC turned off. ')       

    def loadIQcenters(self):
        for ch in range(256):
            I_c = int(self.iq_centers[ch].real/2**3)
            Q_c = int(self.iq_centers[ch].imag/2**3)

            center = (I_c<<16) + (Q_c<<0)
            self.roach.write_int('conv_phase_centers', center)
            self.roach.write_int('conv_phase_load_centers', (ch<<1)+(1<<0))
            self.roach.write_int('conv_phase_load_centers', 0)

    def select_bins(self, readout_freqs):
        fft_len = 2**9
        bins = ''
        i = 0
        residuals = []
        for f in readout_freqs:
            fft_bin = int(round(f*fft_len/self.sampleRate))
            fft_freq = fft_bin*self.sampleRate/fft_len
            freq_residual = round((f - fft_freq)/self.freqRes)*self.freqRes
            residuals.append(freq_residual)
            bins = bins + struct.pack('>l', fft_bin)
            self.roach.write_int('bins', fft_bin)
            self.roach.write_int('load_bins', (i<<1) + (1<<0))
            self.roach.write_int('load_bins', (i<<1) + (0<<0))
            i = i + 1
        self.status_text.setText('done writing LUTs. ')
        return residuals
  
    def loadLUTs(self):
        self.scale_factor = 1.
        self.iq_centers = numpy.array([0.+0j]*256)
        
        # Loads the DAC and DDS LUTs from file.  As well as the IQ loop centers.
        if self.dacStatus == 'off':
            self.roach.write_int('startDAC', 0)
        else:
            self.toggleDAC()

        saveDir = str(self.textbox_lutDir.text())
        #saveDir = str(os.environ['PWD'] + '/'+ self.textbox_lutDir.text())            
        f = open(saveDir+'luts.dat', 'r')
        binaryData = f.read()

        self.roach.write('dram_memory', binaryData)

        x = numpy.loadtxt(saveDir+'centers.dat')
        N_freqs = len(x[:,0])
        for n in range(N_freqs):
            self.iq_centers[n] = complex(x[n,0], x[n,1])
        
        #    Select and write bins for first stage of channelizer.
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + 512e6
        freqs_dds = [0 for j in range(256)]
        for n in range(len(freqs)):
            freqs_dds[n] = round((freqs[n]-f_base)/self.freqRes)*self.freqRes
        freq_residuals = self.select_bins(freqs_dds)
        
        print 'LUTs and IQ centers loaded from file.'
        self.loadIQcenters()
        self.toggleDAC()
   
    def importFreqs(self):
        freqFile =str(self.textbox_freqFile.text())
        self.loadCustomAtten()
        try:
            x = numpy.loadtxt(freqFile) 
            x_string = ''
            for i in range(len(self.customResonators)):
                if self.customResonators[i][1]!=-1:
                    x[i+1,0]=self.customResonators[i][0]
                    x[i+1,3]=self.customResonators[i][1]
        
            self.previous_scale_factor = x[0,0] 
            N_freqs = len(x[1:,0])
            self.numFreqs=N_freqs
            for l in x[1:,0]:
                x_string = x_string + str(l*1e9) + '\n'
            
            self.iq_centers = numpy.array([0.+0j]*256)
            for n in range(N_freqs):
                #for n in range(256):
                self.iq_centers[n] = complex(x[n+1,1], x[n+1,2])
            
            self.attens = x[1:,3]
            self.textedit_DACfreqs.setText(x_string)
            self.findDeletedResonators()
            print 'Freq/Atten loaded from',freqFile
            self.status_text.setText('Freq/Atten loaded')
            
            self.loadCustomThresholds()
        except IOError:
            print 'No such file or directory:',freqFile
            self.status_text.setText('IOError')

    def findDeletedResonators(self):
        for i in range(len(self.customResonators)):
            if self.customResonators[i][1] >=99:
                self.zeroChannels[i] = 1
            else:
                self.zeroChannels[i] = 0 #needed so you can undelete resonators

    def loadCustomAtten(self):
        freqFile =str(self.textbox_freqFile.text())
        newFreqFile = freqFile[:-4] + '_NEW.txt'
        try:
            y=numpy.loadtxt(newFreqFile)
            self.customResonators=numpy.array([[0.0,-1]]*256)
            if type(y[0]) == numpy.ndarray:
                for arr in y:
                    self.customResonators[int(arr[0])]=arr[1:3]
            else:
                self.customResonators[int(y[0])]=y[1:3]
            print 'Loaded custom resonator freq/atten from',newFreqFile
        except IOError:
            pass

    def displayResonatorProperties(self):
        ch=int(self.textbox_channel.text())
        freqFile =str(self.textbox_freqFile.text())
        x = numpy.loadtxt(freqFile)
        #self.loadCustomAtten()
        for i in range(len(self.customResonators)):
            if self.customResonators[i][1]!=-1:
                x[i+1,0]=self.customResonators[i][0]
                x[i+1,3]=self.customResonators[i][1]
        
        #print 'atten: '+str(x[ch,3])
        self.label_attenuation.setText('attenuation: ' + str(int(x[ch+1,3])))
        self.label_frequency.setText('freq (GHz): ' + str(float(x[ch+1,0])))
        self.label_median.setText('median: '+str(self.medians[ch]))
        if self.customThresholds[ch] != 360.0:
            self.label_threshold.setText('threshold: '+str(self.customThresholds[ch]))
        else:
            self.label_threshold.setText('threshold: '+str(self.thresholds[ch]))

        
    def importFIRcoeffs(self):
        coeffsFile =str(self.textbox_coeffsFile.text())
        self.fir = numpy.loadtxt(coeffsFile)
        print self.fir
  
    def file_dialog(self):
        print 'add dialog box here'
        #self.newdatadir = QFileDialog.getExistingDirectory(self, str("Choose SaveDirectory"), "",QFileDialog.ShowDirsOnly)
         #if len(self.newdatadir) > 0:
          #   self.datadir = self.newdatadir
           #  print self.datadir
             #self.ui.data_directory_lineEdit.setText(self.datadir) #put new path name in line edit
            # self.button_saveDir.setText(str(self.datadir))
             
    def create_main_frame(self):
        self.main_frame = QWidget()
        
        # Create the mpl Figure and FigCanvas objects. 
        self.dpi = 100
        self.fig = Figure((9.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        self.axes0 = self.fig.add_subplot(121)
        self.axes1 = self.fig.add_subplot(122)
        cid=self.canvas.mpl_connect('button_press_event', self.setCustomThreshold)
        
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Roach board's IP address
        self.textbox_roachIP = QLineEdit('10.0.0.1%d'%roachNum)
        self.textbox_roachIP.setMaximumWidth(200)
        label_roachIP = QLabel('Roach IP Address:')

        # Start connection to roach.
        self.button_openClient = QPushButton("(1)Open Client")
        self.button_openClient.setMaximumWidth(100)
        self.connect(self.button_openClient, SIGNAL('clicked()'), self.openClient)
        
        # DAC Frequencies.
        self.textedit_DACfreqs = QTextEdit()
        self.textedit_DACfreqs.setMaximumWidth(170)
        self.textedit_DACfreqs.setMaximumHeight(100)
        label_DACfreqs = QLabel('DAC Freqs:')
    
        # File with frequencies/attens
        self.textbox_freqFile = QLineEdit('/home/sean/data/20121006/ps_freq%d.txt'%roachNum)
        self.textbox_freqFile.setMaximumWidth(200)

        # Import freqs from file.
        self.button_importFreqs = QPushButton("(2)Load freqs")
        self.button_importFreqs.setMaximumWidth(200)
        self.connect(self.button_importFreqs, SIGNAL('clicked()'), self.importFreqs)   

        # File with FIR coefficients
        self.textbox_coeffsFile = QLineEdit('/home/sean/data/common/matched_r4p46.txt')
        self.textbox_coeffsFile.setMaximumWidth(200)

        # Import FIR coefficients from file.
        self.button_importFIRcoeffs = QPushButton("Import FIR coeffs.")
        self.button_importFIRcoeffs.setMaximumWidth(200)
        self.connect(self.button_importFIRcoeffs, SIGNAL('clicked()'), self.importFIRcoeffs) 

        # Channel increment by 1.
        self.button_channelInc = QPushButton("Channel++")
        self.button_channelInc.setMaximumWidth(100)
        self.connect(self.button_channelInc, SIGNAL('clicked()'), self.channelInc)

        # Load FIR coefficients.
        self.button_loadFIRcoeffs = QPushButton("(3)load FIR")
        self.button_loadFIRcoeffs.setMaximumWidth(170)
        self.connect(self.button_loadFIRcoeffs, SIGNAL('clicked()'), self.loadFIRcoeffs)

        # Load thresholds.
        self.button_loadThresholds = QPushButton("(4)load thresholds")
        self.button_loadThresholds.setMaximumWidth(170)
        self.connect(self.button_loadThresholds, SIGNAL('clicked()'), self.loadThresholds)

        # remove custom threshold button
        self.button_rmCustomThreshold = QPushButton("remove custom threshold")
        self.button_rmCustomThreshold.setMaximumWidth(170)
        self.connect(self.button_rmCustomThreshold, SIGNAL('clicked()'), self.rmCustomThreshold)
        
        # Channel to measure
        self.textbox_channel = QLineEdit('0')
        self.textbox_channel.setMaximumWidth(50)

        # threshold N*sigma
        self.textbox_Nsigma = QLineEdit('2.5')
        self.textbox_Nsigma.setMaximumWidth(50)
        label_Nsigma = QLabel('sigma       ')
        
        # Time snapshot of a single channel
        self.button_snapshot = QPushButton("snapshot")
        self.button_snapshot.setMaximumWidth(170)
        self.connect(self.button_snapshot, SIGNAL('clicked()'), self.snapshot)            

        # Long time snapshot of a single channel
        self.button_longsnapshot = QPushButton("longsnapshot")
        self.button_longsnapshot.setMaximumWidth(170)
        self.connect(self.button_longsnapshot, SIGNAL('clicked()'), self.longsnapshot)            
        
        # Read pulses
        self.button_readPulses = QPushButton("Read pulses")
        self.button_readPulses.setMaximumWidth(170)
        self.connect(self.button_readPulses, SIGNAL('clicked()'), self.readPulses)   
        
        # Seconds for "read pulses."
        self.textbox_seconds = QLineEdit('1')
        self.textbox_seconds.setMaximumWidth(50)
        
        # lengths of 2 ms for defining thresholds.
        self.textbox_timeLengths = QLineEdit('10')
        self.textbox_timeLengths.setMaximumWidth(50)
        label_timeLengths = QLabel('* 2 msec       ')


        # lengths of 2 ms steps to combine in a snapshot.
        self.textbox_snapSteps = QLineEdit('10')
        self.textbox_snapSteps.setMaximumWidth(50)
        label_snapSteps = QLabel('* 2 msec')

        # lengths of 2 ms steps to combine in a snapshot.
        self.textbox_longsnapSteps = QLineEdit('1')
        self.textbox_longsnapSteps.setMaximumWidth(50)
        label_longsnapSteps = QLabel('* sec')

        #median
        self.label_median = QLabel('median: 0.0000')
        self.label_median.setMaximumWidth(170)

        #threshold
        self.label_threshold = QLabel('threshold: 0.0000')
        self.label_threshold.setMaximumWidth(170)

        #attenuation
        self.label_attenuation = QLabel('attenuation: 0')
        self.label_attenuation.setMaximumWidth(170)

        #frequency
        self.label_frequency = QLabel('freq (GHz): 0.0000')
        self.label_frequency.setMaximumWidth(170)
        
        # Add widgets to window.
        gbox0 = QVBoxLayout()
        hbox00 = QHBoxLayout()
        hbox00.addWidget(self.textbox_roachIP)
        hbox00.addWidget(self.button_openClient)
        gbox0.addLayout(hbox00)
        hbox01 = QHBoxLayout()
        hbox01.addWidget(self.textbox_freqFile)
        hbox01.addWidget(self.button_importFreqs)
        gbox0.addLayout(hbox01)
        hbox02 = QHBoxLayout()
        hbox02.addWidget(self.textbox_coeffsFile)
        hbox02.addWidget(self.button_importFIRcoeffs)
        hbox02.addWidget(self.button_loadFIRcoeffs)
        gbox0.addLayout(hbox02)
        hbox03 = QHBoxLayout()
        hbox03.addWidget(self.textbox_timeLengths)
        hbox03.addWidget(label_timeLengths)
        hbox03.addWidget(self.textbox_Nsigma)
        hbox03.addWidget(label_Nsigma)
        hbox03.addWidget(self.button_loadThresholds)
        gbox0.addLayout(hbox03)
        
        gbox1 = QVBoxLayout()
        gbox1.addWidget(label_DACfreqs)
        gbox1.addWidget(self.textedit_DACfreqs)

        gbox2 = QVBoxLayout()
        hbox20 = QHBoxLayout()
        hbox20.addWidget(self.textbox_channel)
        hbox20.addWidget(self.button_channelInc)
        gbox2.addLayout(hbox20)
        hbox21 = QHBoxLayout()
        hbox21.addWidget(self.button_snapshot)
        hbox21.addWidget(self.textbox_snapSteps)
        hbox21.addWidget(label_snapSteps)
        gbox2.addLayout(hbox21)
        hbox22 = QHBoxLayout()
        hbox22.addWidget(self.button_longsnapshot)
        hbox22.addWidget(self.textbox_longsnapSteps)
        hbox22.addWidget(label_longsnapSteps)
        gbox2.addLayout(hbox22)
        gbox2.addWidget(self.button_rmCustomThreshold)
        hbox23 = QHBoxLayout()
        hbox23.addWidget(self.textbox_seconds)
        hbox23.addWidget(self.button_readPulses)
        gbox2.addLayout(hbox23)

        gbox3 = QVBoxLayout()
        gbox3.addWidget(self.label_median)
        gbox3.addWidget(self.label_threshold)
        gbox3.addWidget(self.label_attenuation)
        gbox3.addWidget(self.label_frequency)

        hbox = QHBoxLayout()
        hbox.addLayout(gbox0)
        hbox.addLayout(gbox1)     
        hbox.addLayout(gbox2)
        hbox.addLayout(gbox3)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
  
    def create_status_bar(self):
        self.status_text = QLabel("Awaiting orders.")
        self.statusBar().addWidget(self.status_text, 1)
        
    def create_menu(self):        
        self.file_menu = self.menuBar().addMenu("&File")
        
        load_file_action = self.create_action("&Save plot",shortcut="Ctrl+S", slot=self.save_plot, tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close, shortcut="Ctrl+Q", tip="Close the application")
        
        self.add_actions(self.file_menu, (load_file_action, None, quit_action))
        
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About the demo')
        
        self.add_actions(self.help_menu, (about_action,))

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '',file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def on_about(self):
        msg = """ Message to user goes here.
        """
        QMessageBox.about(self, "MKID-ROACH software demo", msg.strip())
예제 #34
0
class QArkMplPlotWidget(QtGui.QWidget):
    """
    """
    VIEW_MODE__PLOT = 1
    VIEW_MODE__IMAGESHOW = 2
    VIEW_MODE__MATRIXSHOW = 4
    VIEW_MODE__WIREFRAME = 8
    VIEW_MODE__SURFACE = 16
    VIEW_MODE__COLORMESH = 32

    def __init__(self, parent=None):
        """
        """
        super(QArkMplPlotWidget, self).__init__(parent=parent)
        self.initUi()
        self.initConnection()
        self.t_axes = {}

    def initUi(self):
        """
        """
        self.setObjectName(_fromUtf8("qArkMplPlotWidget"))
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        vbox = QtGui.QVBoxLayout()

        #--------------------------------------------------------------------------------
        # Plot zone
        #--------------------------------------------------------------------------------
        self.dpi = 70
        #self.figure = plt.Figure((10.0, 10.0), dpi=self.dpi)
        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        print(self)
        self.canvas.setParent(self)
        self.mpl_toolbar = NavigationToolbar(self.canvas, self)
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        self.setLayout(vbox)

    def initConnection(self):
        """
        """
        pass

    def initAxe(self, _u_c, _u_mode):
        if _u_mode is self.__class__.VIEW_MODE__PLOT:
            self.t_axes[_u_c] = self.fig.add_subplot(_u_c)
        elif _u_mode is self.__class__.VIEW_MODE__IMAGESHOW:
            self.t_axes[_u_c] = self.fig.add_subplot(_u_c)
        elif _u_mode is self.__class__.VIEW_MODE__MATRIXSHOW:
            self.t_axes[_u_c] = self.fig.add_subplot(_u_c)
        elif _u_mode is self.__class__.VIEW_MODE__WIREFRAME:
            self.t_axes[_u_c] = self.fig.add_subplot(_u_c, projection='3d')
        elif _u_mode is self.__class__.VIEW_MODE__SURFACE:
            self.t_axes[_u_c] = self.fig.add_subplot(_u_c, projection='3d')
        elif _u_mode is self.__class__.VIEW_MODE__COLORMESH:
            self.t_axes[_u_c] = self.fig.add_subplot(_u_c)
        return self.t_axes[_u_c]

    def enableCurrentFigure(self):
        plt.figure(self.figure.number)

    def displayPlot(self):
        self.canvas.draw()

    def savePlot(self, _s_filename):
        self.canvas.print_figure(_s_filename)

    def setPlotter(self, _o_plotter):
        self.o_plotter = _o_plotter
        self.enableCurrentFigure()
        self.o_plotter.setFigure(self.figure)
        self.o_plotter.plot()
        self.displayPlot()

    @QtCore.pyqtSlot()
    def updatePlot(self):
        self.o_plotter.plot()
        self.displayPlot()
예제 #35
0
class GNSSAzEl_window(QtGui.QMainWindow, Ui_GNSSAzElWindow):
    def __init__(self):
        super(GNSSAzEl_window, self).__init__()
        self.setupUi(self)
        self.init_Ui()

    def init_Ui(self):

        self.create_menuActions()
        self.btn_close.clicked.connect(self.close)

        self.dpi = 100
        self.fig = Figure((6.6, 6.6), dpi=self.dpi)
        self.fig.patch.set_facecolor('none')
        self.canvas = FigureCanvas(self.fig)
        # Position as left, top, width, height
        self.canvas.setGeometry(QtCore.QRect(40, 60, 600, 600))
        self.canvas.setParent(self)
        self.drawAzElPlt()

        self.checkBoxGPS.clicked.connect(self.refreshAzElPlt)
        self.checkBoxGLONASS.clicked.connect(self.refreshAzElPlt)
        self.checkBoxGALILEO.clicked.connect(self.refreshAzElPlt)
        self.checkBoxBEIDOU.clicked.connect(self.refreshAzElPlt)

        self.refreshtimer = QtCore.QTimer()
        self.refreshtimer.start(5000)  #ms
        self.refreshtimer.timeout.connect(self.refreshAzElPlt)

        self.btn_close.clicked.connect(self.refreshtimer.stop)

    def drawAzElPlt(self):
        """
	Draws the GNSS Az-El plot.

	"""

        self.grid = rc('grid', color='green', linewidth=0.5, linestyle='-')
        self.grid = rc('xtick', labelsize=15)
        self.grid = rc('ytick', labelsize=10)

        self.ax = self.fig.add_axes([0.1, 0.1, 0.8, 0.8],
                                    projection='polar',
                                    axisbg='#d5de9c')
        self.ax.set_rmax(90)

        self.ax.set_rgrids([10, 20, 30, 40, 50, 60, 70, 80, 90], angle=0)
        self.ax.set_theta_offset(0.5 * math.pi)
        self.ax.set_theta_direction(-1)

        self.ax.set_title(
            "GNSS satellites on the local horizon",
            va='bottom',
        )
        self.ax.set_yticklabels(map(str, range(80, 0, -10)))
        self.ax.set_xticklabels(['N', '', 'E', '', 'S', '', 'W', ''])

        self.ax.set_autoscalex_on(False)
        self.ax.set_autoscaley_on(False)

        if self.checkBoxGPS.isChecked() == True:
            [GPSname, phi_GPS, r_GPS] = satellites.SatCompute(
                'visible', 'GPS')  # fills the list with all GPS satellites
            GPSname = [
                j.split()[-2].replace("(", "") +
                j.split()[-1].replace(")", "") for j in GPSname
            ]  # shortens the displayed satellites' names on the plot
            self.ax.plot(phi_GPS, r_GPS, 'ro', label='GPS')
            for i, txt in enumerate(GPSname):
                self.ax.annotate(txt, (phi_GPS[i], r_GPS[i]))

        if self.checkBoxGLONASS.isChecked() == True:
            [GLONASSname, phi_GLONASS, r_GLONASS] = satellites.SatCompute(
                'visible',
                'COSMOS')  # fills the list with all GLONASS satellites
            GLONASSname = [j[13:16] for j in GLONASSname]
            self.ax.plot(phi_GLONASS, r_GLONASS, 'bo', label='GLONASS')
            for i, txt in enumerate(GLONASSname):
                self.ax.annotate(txt, (phi_GLONASS[i], r_GLONASS[i]))

        if self.checkBoxGALILEO.isChecked() == True:
            [GALILEOname, phi_GALILEO, r_GALILEO] = satellites.SatCompute(
                'visible',
                'GSAT')  # fills the list with all GALILEO satellites
            GALILEOname = [
                j.split()[-2].replace("(", "") +
                j.split()[-1].replace(")", "") for j in GALILEOname
            ]
            self.ax.plot(phi_GALILEO, r_GALILEO, 'go', label='GALILEO')
            for i, txt in enumerate(GALILEOname):
                self.ax.annotate(txt, (phi_GALILEO[i], r_GALILEO[i]))
        if self.checkBoxBEIDOU.isChecked() == True:
            [BEIDOUname, phi_BEIDOU, r_BEIDOU] = satellites.SatCompute(
                'visible',
                'BEIDOU')  # fills the list with all BEIDOU satellites
            BEIDOUname = [j.split()[-1] for j in BEIDOUname]
            self.ax.plot(phi_BEIDOU, r_BEIDOU, 'ko', label='BEIDOU')
            for i, txt in enumerate(BEIDOUname):
                self.ax.annotate(txt, (phi_BEIDOU[i], r_BEIDOU[i]))

        self.canvas.draw()

    def refreshAzElPlt(self):
        """
	    Refreshes the drawn plot
	"""
        self.ax.clear()
        self.drawAzElPlt()

    def create_menuActions(self):
        """
        Creates actions for the menubar of the GNSS Az-El window.
        :return: Nothing
        """
        save_file_action = self.create_action(
            "&Save current view",
            shortcut="Ctrl+S",
            slot=self.save_AzElPlot,
            tip="Saves current Azimuth-Elevation view as an image.")

        quit_action = self.create_action("&Quit",
                                         slot=self.close,
                                         shortcut="Ctrl+Q",
                                         tip="Closes current window")

        about_action = self.create_action(
            "&About",
            shortcut='F1',
            slot=self.on_about,
            tip='Displays additional information.')

        self.add_actions(self.file_menu, (save_file_action, None, quit_action))

        self.add_actions(self.help_menu, (about_action, ))

    def add_actions(self, target, actions):

        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(self,
                      text,
                      slot=None,
                      shortcut=None,
                      icon=None,
                      tip=None,
                      checkable=False,
                      signal="triggered()"):

        action = QtGui.QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, QtCore.SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_AzElPlot(self):
        """
        Saves the current GNSS Az-El plot
        """
        file_choices = "PNG (*.png)|*.png"

        path = unicode(
            QtGui.QFileDialog.getSaveFileName(self, 'Save file', '',
                                              file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)

    def on_about(self):
        """
        A message of the help option
        """
        msg = """

        This window displays current positions of GNSS satellites on the local horizon. Positions computed using two-line element set (TLE) data.
        """
        QtGui.QMessageBox.about(self, "GNSS Az-El view", msg.strip())
예제 #36
0
class MplFigureCellWidget(QCellWidget):
    """
    MplFigureCellWidget is the actual QWidget taking the FigureManager
    as a child for displaying figures
    
    """
    def __init__(self, parent=None):
        """ MplFigureCellWidget(parent: QWidget) -> MplFigureCellWidget
        Initialize the widget with its central layout
        
        """
        QCellWidget.__init__(self, parent)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        centralLayout = QtGui.QVBoxLayout()
        self.setLayout(centralLayout)
        centralLayout.setMargin(0)
        centralLayout.setSpacing(0)        
        # self.figManager = pylab.get_current_fig_manager()
        # self.figManager = None
        # self.figNumber = None
        self.canvas = None
        self.figure = None
        self.figManager = None
        self.toolBarType = MplFigureCellToolBar
        self.mplToolbar = None

    # def getFigManager(self):
    #     if self.figNumber is not None:
    #         pylab.figure(self.figNumber)
    #         return pylab.get_current_fig_manager()
    #     return None

    # def getFigure(self):
    #     if self.figNumber is not None:
    #         return pylab.figure(self.figNumber)
    #     return None

    def updateContents(self, inputPorts):
        """ updateContents(inputPorts: tuple) -> None
        Update the widget contents based on the input data
        
        """
        (fig, ) = inputPorts
        if not self.figure or self.figure.number != fig.figInstance.number:
            if self.layout().count() > 0:
                self.layout().removeWidget(self.canvas)

            self.figure = fig.figInstance
                
            # self.figure.set_size_inches(8.0,6.0)
            self.canvas = FigureCanvasQTAgg(self.figure)
            self.mplToolbar = MplNavigationToolbar(self.canvas, None)
            self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                      QtGui.QSizePolicy.Expanding)
            # self.figManager = FigureManagerBase(self.canvas, self.figure.number)
            self.layout().addWidget(self.canvas)

            # Update the new figure canvas
            # self.canvas.draw()
            # self.layout().addWidget(self.getFigManager().window)

        # Update the new figure canvas
        # self.getFigManager().canvas.draw()            

        # # Replace the old one with the new one
        # if newFigManager!=self.figManager:
            
        #     # Remove the old figure manager
        #     if self.figManager:
        #         self.figManager.window.hide()
        #         self.layout().removeWidget(self.figManager.window)

        #     # Add the new one in
        #     self.layout().addWidget(newFigManager.window)

        #     # Destroy the old one if possible
        #     if self.figManager:
                
        #         try:                    
        #             pylab.close(self.figManager.canvas.figure)
        #         # There is a bug in Matplotlib backend_qt4. It is a
        #         # wrong command for Qt4. Just ignore it and continue
        #         # to destroy the widget
        #         except:
        #             pass
                
        #         self.figManager.window.deleteLater()
        #         del self.figManager

        #     # Save back the manager
        #     self.figManager = newFigManager
        #     self.update()

    def keyPressEvent(self, event):
        print "KEY PRESS:",  event.key()
        self.canvas.keyPressEvent(event)

    def keyReleaseEvent(self, event):
        print "KEY RELEASE:", event.key()
        self.canvas.keyReleaseEvent(event)

    def deleteLater(self):
        """ deleteLater() -> None        
        Overriding PyQt deleteLater to free up resources
        
        """
        # Destroy the old one if possible
        if self.figure is not None:
            # self.getFigManager().window.deleteLater()
            print "pylab:", pylab
            print "self.figure:", self.figure
            pylab.close(self.figure)
            
        # if self.figManager:
            
        #     try:                    
        #         pylab.close(self.figManager.canvas.figure)
        #     # There is a bug in Matplotlib backend_qt4. It is a
        #     # wrong command for Qt4. Just ignore it and continue
        #     # to destroy the widget
        #     except:
        #         pass
            
        #     self.figManager.window.deleteLater()
        QCellWidget.deleteLater(self)

    def grabWindowPixmap(self):
        """ grabWindowPixmap() -> QPixmap
        Widget special grabbing function
        
        """
        # pylab.figure(self.figNumber)
        # figManager = pylab.get_current_fig_manager()
        return QtGui.QPixmap.grabWidget(self.canvas)

    def dumpToFile(self, filename):
        previous_size = tuple(self.figure.get_size_inches())
        self.figure.set_size_inches(8.0,6.0)
        self.canvas.print_figure(filename)
        self.figure.set_size_inches(previous_size[0],previous_size[1])
        self.canvas.draw()
        
    def saveToPDF(self, filename):
        previous_size = tuple(self.figure.get_size_inches())
        self.figure.set_size_inches(8.0,6.0)
        self.canvas.print_figure(filename)
        self.figure.set_size_inches(previous_size[0],previous_size[1])
        self.canvas.draw()
예제 #37
0
class GridDisplay(Component):
    '''
    Class to create a display plot, using a Grid structure.
    '''

    Vgrid = None  #: see :ref:`shared_variable`
    Vfield = None  #: see :ref:`shared_variable`
    VlevelZ = None \
        #: see :ref:`shared_variable`, only used if plot_type="gridZ"
    VlevelY = None \
        #: see :ref:`shared_variable`, only used if plot_type="gridY"
    VlevelX = None \
        #: see :ref:`shared_variable`, only used if plot_type="gridX"
    Vcmap = None  #: see :ref:`shared_variable`

    @classmethod
    def guiStart(self, parent=None):
        '''Graphical interface for starting this class'''
        args = _DisplayStart().startDisplay()
        return self(**args), True

    def __init__(self, Vgrid, Vfield, VlevelZ=None, VlevelY=None,
                 VlevelX=None, Vlims=None, Vcmap=None, plot_type="gridZ",
                 name="Display", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        Vgrid : :py:class:`~artview.core.core.Variable` instance
            grid signal variable.
        Vfield : :py:class:`~artview.core.core.Variable` instance
            Field signal variable.
        [Optional]
        VlevelZ : :py:class:`~artview.core.core.Variable` instance
            Signal variable for vertical level, only used if
            plot_type="gridZ". If None start with value zero.
        VlevelY : :py:class:`~artview.core.core.Variable` instance
            Signal variable for latitudinal level, only used if
            plot_type="gridY". If None start with value zero.
        VlevelX : :py:class:`~artview.core.core.Variable` instance
            Signal variable for longitudinal level, only used if
            plot_type="gridX". If None start with value zero.
        Vlims : :py:class:`~artview.core.core.Variable` instance
            Limits signal variable.
            A value of None will instantiate a limits variable.
        Vcmap : :py:class:`~artview.core.core.Variable` instance
            Colormap signal variable.
            A value of None will instantiate a colormap variable.
        plot_type : "gridZ", "gridY" or "gridX"
            Define plot type, "gridZ" will plot a Z level, that is a XY
            plane. Analog for "gridY" and "gridZ"
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        Notes
        -----
        This class records the selected button and passes the
        change value back to variable.
        '''
        super(GridDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.basemap = None
        # Set up signal, so that DISPLAY can react to
        # external (or internal) changes in grid, field,
        # lims and level (expected to be Core.Variable instances)
        # The capital V so people remember using ".value"
        self.Vgrid = Vgrid
        self.Vfield = Vfield
        if VlevelZ is None:
            self.VlevelZ = Variable(0)
        else:
            self.VlevelZ = VlevelZ
        if VlevelY is None:
            self.VlevelY = Variable(0)
        else:
            self.VlevelY = VlevelY
        if VlevelX is None:
            self.VlevelX = Variable(0)
        else:
            self.VlevelX = VlevelX
        if Vlims is None:
            self.Vlims = Variable(None)
        else:
            self.Vlims = Vlims

        if Vcmap is None:
            self.Vcmap = Variable(None)
        else:
            self.Vcmap = Vcmap

        self.sharedVariables = {"Vgrid": self.Newgrid,
                                "Vfield": self.NewField,
                                "Vlims": self.NewLims,
                                "Vcmap": self.NewCmap, }

        self.change_plot_type(plot_type)

        # Connect the components
        self.connectAllVariables()

        # Set plot title and colorbar units to defaults
        self.title = self._get_default_title()
        self.units = self._get_default_units()

        # set default latlon lines
        self.lat_lines = np.linspace(-90, 90, num=181)
        self.lon_lines = np.linspace(-180, 180, num=361)

        # Find the PyArt colormap names
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create tool dictionary
        self.tools = {}

        # Set up Default limits and cmap
        if Vlims is None:
            self._set_default_limits(strong=False)
        if Vcmap is None:
            self._set_default_cmap(strong=False)

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Initialize grid variable
        self.Newgrid(None, None, True)
        self._update_fig_ax()
        self.show()

    def keyPressEvent(self, event):
        '''Allow level adjustment via the Up-Down arrow keys.'''
        if event.key() == QtCore.Qt.Key_Up:
            self.LevelSelectCmd(self.Vlevel.value + 1)
        elif event.key() == QtCore.Qt.Key_Down:
            self.LevelSelectCmd(self.Vlevel.value - 1)
        else:
            super(GridDisplay, self).keyPressEvent(event)

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(8)

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add buttons along display for user control
        self.addButtons()
        self.setUILayout()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    ##################################
    # User display interface methods #
    ##################################
    def addButtons(self):
        '''Add a series of buttons for user control over display.'''
        # Create the Display controls
        self._add_displayBoxUI()
        # Create the Level controls
        self._add_levelBoxUI()
        # Create the Field controls
        self._add_fieldBoxUI()
        # Create the Tools controls
        self._add_toolsBoxUI()
        # Create the Informational label at top
        self._add_infolabel()

    def setUILayout(self):
        '''Setup the button/display UI layout.'''
        self.layout.addWidget(self.levelBox, 0, 0)
        self.layout.addWidget(self.fieldBox, 0, 1)
        self.layout.addWidget(self.dispButton, 0, 2)
        self.layout.addWidget(self.toolsButton, 0, 3)
        self.layout.addWidget(self.infolabel, 0, 4)

    #############################
    # Functionality methods #
    #############################

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(self.Vlims.value,
                                             self.Vcmap.value, self.name)
        if change == 1:
            self.Vcmap.change(cmap, False)
            self.Vlims.change(limits)

    def _fillLevelBox(self):
        '''Fill in the Level Window Box with current levels.'''
        self.levelBox.clear()
        self.levelBox.addItem("Level Window")
        # Loop through and create each level button
        if self.plot_type == "gridZ":
            levels = self.Vgrid.value.axes['z_disp']['data']
        elif self.plot_type == "gridY":
            levels = self.Vgrid.value.axes['y_disp']['data']
        elif self.plot_type == "gridX":
            levels = self.Vgrid.value.axes['x_disp']['data']

        for nlevel in range(len(levels)):
            btntxt = "%2.1f m (level %d)" % (levels[nlevel], nlevel+1)
            self.levelBox.addItem(btntxt)

    def _fillFieldBox(self):
        '''Fill in the Field Window Box with current variable names.'''
        self.fieldBox.clear()
        self.fieldBox.addItem("Field Window")
        # Loop through and create each field button
        for field in self.fieldnames:
            self.fieldBox.addItem(field)

    def _levelAction(self, text):
        '''Define action for Level Button selection.'''
        if text == "Level Window":
            self._open_levelbuttonwindow()
        else:
            nlevel = int(text.split("(level ")[1][:-1])-1
            self.LevelSelectCmd(nlevel)

    def _fieldAction(self, text):
        '''Define action for Field Button selection.'''
        if text == "Field Window":
            self._open_fieldbuttonwindow()
        else:
            self.FieldSelectCmd(str(text))

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog_with_reset(
            self.title, "Plot Title", "Title:", self._get_default_title())
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog_with_reset(
            self.units, "Plot Units", "Units:", self._get_default_units())
        if entry is True:
            self.units = val
            self._update_plot()

    def _open_levelbuttonwindow(self):
        '''Open a LevelButtonWindow instance.'''
        from .level import LevelButtonWindow
        if self.plot_type == "gridZ":
            self.levelbuttonwindow = LevelButtonWindow(
                self.Vlevel, self.plot_type, Vcontainer=self.Vgrid,
                controlType="radio", name=self.name+" Level Selection",
                parent=self.parent)
        else:
            self.levelbuttonwindow = LevelButtonWindow(
                self.Vlevel, self.plot_type, Vcontainer=self.Vgrid,
                controlType="slider", name=self.name+" Level Selection",
                parent=self.parent)

    def _open_fieldbuttonwindow(self):
        '''Open a FieldButtonWindow instance.'''
        from .field import FieldButtonWindow
        self.fieldbuttonwindow = FieldButtonWindow(
            self.Vgrid, self.Vfield,
            name=self.name+" Field Selection", parent=self.parent)

    def _add_cmaps_to_button(self):
        '''Add a menu to change colormap used for plot.'''
        for cm_name in self.cm_names:
            cmapAction = self.dispCmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap" % cm_name)
            cmapAction.triggered[()].connect(
                lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
            self.dispCmap.setMenu(self.dispCmapmenu)

    def _add_displayBoxUI(self):
        '''Create the Display Options Button menu.'''
        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = dispmenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
        dispTitle = dispmenu.addAction("Change Title")
        dispTitle.setToolTip("Change plot title")
        dispUnit = dispmenu.addAction("Change Units")
        dispUnit.setToolTip("Change units string")
        self.dispCmap = dispmenu.addAction("Change Colormap")
        self.dispCmapmenu = QtGui.QMenu("Change Cmap")
        self.dispCmapmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        dispQuickSave = dispmenu.addAction("Quick Save Image")
        dispQuickSave.setShortcut("Ctrl+D")
        dispQuickSave.setToolTip(
            "Save Image to local directory with default name")
        dispSaveFile = dispmenu.addAction("Save Image")
        dispSaveFile.setShortcut("Ctrl+S")
        dispSaveFile.setStatusTip("Save Image using dialog")

        dispLimits.triggered[()].connect(self._open_LimsDialog)
        dispTitle.triggered[()].connect(self._title_input)
        dispUnit.triggered[()].connect(self._units_input)
        dispQuickSave.triggered[()].connect(self._quick_savefile)
        dispSaveFile.triggered[()].connect(self._savefile)

        self._add_cmaps_to_button()
        self.dispButton.setMenu(dispmenu)

    def _add_levelBoxUI(self):
        '''Create the Level Selection ComboBox.'''
        self.levelBox = QtGui.QComboBox()
        self.levelBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.levelBox.setToolTip(
            "Select level slice to display.\n"
            "'Level Window' will launch popup.\n"
            "Up/Down arrow keys Increase/Decrease level.")

        self.levelBox.activated[str].connect(self._levelAction)

    def _add_fieldBoxUI(self):
        '''Create the Field Selection ComboBox.'''
        self.fieldBox = QtGui.QComboBox()
        self.fieldBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.fieldBox.setToolTip("Select variable/field in data file.\n"
                                 "'Field Window' will launch popup.\n")
        self.fieldBox.activated[str].connect(self._fieldAction)

    def _add_toolsBoxUI(self):
        '''Create the Tools Button menu.'''
        self.toolsButton = QtGui.QPushButton("Toolbox")
        self.toolsButton.setFocusPolicy(QtCore.Qt.NoFocus)
        self.toolsButton.setToolTip("Choose a tool to apply")
        toolmenu = QtGui.QMenu(self)
        toolZoomPan = toolmenu.addAction("Zoom/Pan")
        toolValueClick = toolmenu.addAction("Click for Value")
        toolSelectRegion = toolmenu.addAction("Select a Region of Interest")
        toolReset = toolmenu.addAction("Reset Tools")
        toolDefault = toolmenu.addAction("Reset File Defaults")
        toolZoomPan.triggered[()].connect(self.toolZoomPanCmd)
        toolValueClick.triggered[()].connect(self.toolValueClickCmd)
        toolSelectRegion.triggered[()].connect(self.toolSelectRegionCmd)
        toolReset.triggered[()].connect(self.toolResetCmd)
        toolDefault.triggered[()].connect(self.toolDefaultCmd)
        self.toolsButton.setMenu(toolmenu)

    def _add_infolabel(self):
        '''Create an information label about the display'''
        self.infolabel = QtGui.QLabel("Grid: \n"
                                      "Field: \n"
                                      "Level: ", self)
        self.infolabel.setStyleSheet('color: red; font: italic 10px')
        self.infolabel.setToolTip("Filename not loaded")

    def _update_infolabel(self):
        if self.Vgrid.value is None:
            return
        self.infolabel.setText(
            "Grid: %s\n"
            "Field: %s\n"
            "Level: %d" % (self.Vgrid.value.metadata['instrument_name'],
                           self.Vfield.value,
                           self.Vlevel.value+1))
        if hasattr(self.Vgrid.value, 'filename'):
            self.infolabel.setToolTip(self.Vgrid.value.filename)

    ########################
    # Selectionion methods #
    ########################

    def Newgrid(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vgrid <artview.core.core.Variable>`.

        This will:

        * Update fields and levels lists and MenuBoxes
        * Check grid scan type and reset limits if needed
        * Reset units and title
        * If strong update: update plot
        '''
        # test for None
        if self.Vgrid.value is None:
            self.fieldBox.clear()
            self.levelBox.clear()
            return

        # Get field names
        self.fieldnames = self.Vgrid.value.fields.keys()

        # Check the file type and initialize limts
        self._check_file_type()

        # Update field and level MenuBox
        self._fillLevelBox()
        self._fillFieldBox()

        self.units = self._get_default_units()
        self.title = self._get_default_title()
        if strong:
            self._update_plot()
            self._update_infolabel()

    def NewField(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vfield <artview.core.core.Variable>`.

        This will:

        * Reset colormap
        * Reset units
        * Update fields MenuBox
        * If strong update: update plot
        '''
        self._set_default_cmap(strong=False)
        self.units = self._get_default_units()
        self.title = self._get_default_title()
        idx = self.fieldBox.findText(value)
        self.fieldBox.setCurrentIndex(idx)
        if strong:
            self._update_plot()
            self._update_infolabel()

    def NewLims(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlims <artview.core.core.Variable>`.

        This will:

        * If strong update: update axes
        '''
        if strong:
            self._update_axes()

    def NewCmap(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vcmap <artview.core.core.Variable>`.

        This will:

        * If strong update: update plot
        '''
        if strong:
            self._update_plot()

    def NewLevel(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlevel* <artview.core.core.Variable>`.

        This will:

        * Update level MenuBox
        * If strong update: update plot
        '''
        # +1 since the first one is "Level Window"
        self.levelBox.setCurrentIndex(value+1)
        if strong:
            self._update_plot()
            self._update_infolabel()

    def LevelSelectCmd(self, nlevel):
        '''
        Captures Level selection and update Level
        :py:class:`~artview.core.core.Variable`.
        '''
        if nlevel < 0:
            nlevel = len(self.levels)-1
        elif nlevel >= len(self.levels):
            nlevel = 0
        self.Vlevel.change(nlevel)

    def FieldSelectCmd(self, name):
        '''
        Captures field selection and update field
        :py:class:`~artview.core.core.Variable`.
        '''
        self.Vfield.change(name)

    def cmapSelectCmd(self, cm_name):
        '''Captures colormap selection and redraws.'''
        CMAP = cm_name
        self.Vcmap.value['cmap'] = cm_name
        self.Vcmap.update()

    def toolZoomPanCmd(self):
        '''Creates and connects to a Zoom/Pan instance.'''
        from .tools import ZoomPan
        scale = 1.1
        self.tools['zoompan'] = ZoomPan(
            self.Vlims, self.ax,
            base_scale=scale, parent=self.parent)
        self.tools['zoompan'].connect()

    def toolValueClickCmd(self):
        '''Creates and connects to Point-and-click value retrieval'''
        from .pick_value import ValueClick
        self.tools['valueclick'] = ValueClick(
            self, name=self.name + "ValueClick", parent=self)

    def toolSelectRegionCmd(self):
        '''Creates and connects to Region of Interest instance.'''
        from .select_region import SelectRegion
        self.tools['select_region'] = SelectRegion(
            self, name=self.name + " SelectRegion", parent=self)

    def toolResetCmd(self):
        '''Reset tools via disconnect.'''
        from . import tools
        self.tools = tools.reset_tools(self.tools)

    def toolDefaultCmd(self):
        '''Restore the Display defaults.'''
        from . import tools
        self._set_default_limits()
        self._set_default_cmap()

    def getPathInteriorValues(self, path):
        '''
        Return the bins values path.

        Parameters
        ----------
        path : Matplotlib Path instance

        Returns
        -------
        points: Points
            Points object containing all bins of the current grid
            and level inside path. Axes : 'x_disp', 'y_disp', 'x_disp',
            'x_index', 'y_index', 'z_index'. Fields: just current field

        Notes
        -----
            If Vgrid.value is None, returns None
        '''
        from .tools import interior_grid
        grid = self.Vgrid.value
        if grid is None:
            return None

        xy, idx = interior_grid(path, grid, self.basemap, self.Vlevel.value,
                                self.plot_type)

        if self.plot_type == "gridZ":
            x = xy[:, 0]
            y = xy[:, 1]
            z = np.ones_like(xy[:, 0]) * self.levels[self.VlevelZ.value]
            x_idx = idx[:, 0]
            y_idx = idx[:, 1]
            z_idx = np.ones_like(idx[:, 0]) * self.VlevelZ.value
        elif self.plot_type == "gridY":
            x = xy[:, 0] * 1000.
            z = xy[:, 1] * 1000.
            y = np.ones_like(xy[:, 0]) * self.levels[self.VlevelY.value]
            x_idx = idx[:, 0]
            z_idx = idx[:, 1]
            y_idx = np.ones_like(idx[:, 0]) * self.VlevelY.value
        elif self.plot_type == "gridX":
            z = xy[:, 0] * 1000.
            y = xy[:, 1] * 1000.
            x = np.ones_like(xy[:, 0]) * self.levels[self.VlevelX.value]
            z_idx = idx[:, 0]
            y_idx = idx[:, 1]
            x_idx = np.ones_like(idx[:, 0]) * self.VlevelX.value

        xaxis = {'data':  x,
                 'long_name': 'X-coordinate in Cartesian system',
                 'axis': 'X',
                 'units': 'm'}

        yaxis = {'data':  y,
                 'long_name': 'Y-coordinate in Cartesian system',
                 'axis': 'Y',
                 'units': 'm'}

        zaxis = {'data':  z,
                 'long_name': 'Z-coordinate in Cartesian system',
                 'axis': 'Z',
                 'units': 'm'}

        field = grid.fields[self.Vfield.value].copy()
        field['data'] = grid.fields[self.Vfield.value]['data'][
            z_idx, y_idx, x_idx]

        x_idx = {'data': x_idx,
                 'long_name': 'index in nx dimension'}
        y_idx = {'data': y_idx,
                 'long_name': 'index in ny dimension'}
        z_idx = {'data': z_idx,
                 'long_name': 'index in nz dimension'}

        axes = {'x_disp': xaxis,
                'y_disp': yaxis,
                'z_disp': zaxis,
                'x_index': x_idx,
                'y_index': y_idx,
                'z_index': z_idx, }

        fields = {self.Vfield.value: field}

        points = Points(fields, axes, grid.metadata.copy(), xy.shape[0])

        return points

    def getNearestPoints(self, xdata, ydata):
        '''
        Return the bins values nearest to point.

        Parameters
        ----------
        xdata, ydata : float

        Returns
        -------
        x, y, z, value, x_idx, y_idx, z_idx: ndarray
            Truplet of 1arrays containing x,y,z coordinate, current field
            value, x, y and z index.

        Notes
        -----
            If Vgrid.value is None, returns None
        '''
        from .tools import nearest_point_grid
        grid = self.Vgrid.value

        # map center
        lat0 = self.Vgrid.value.axes['lat']['data'][0]
        lon0 = self.Vgrid.value.axes['lon']['data'][0]

        if grid is None:
            return (np.array([]),)*7

        if self.plot_type == "gridZ":
            idx = nearest_point_grid(
                grid, self.basemap, self.levels[self.VlevelZ.value], ydata,
                xdata)
        elif self.plot_type == "gridY":
            idx = nearest_point_grid(
                grid, self.basemap, ydata * 1000.,
                self.levels[self.VlevelY.value], xdata * 1000.)
        elif self.plot_type == "gridX":
            idx = nearest_point_grid(
                grid, self.basemap, ydata * 1000., xdata * 1000.,
                self.levels[self.VlevelX.value])
        aux = (grid.axes['x_disp']['data'][idx[:, 2]],
               grid.axes['y_disp']['data'][idx[:, 1]],
               grid.axes['z_disp']['data'][idx[:, 0]],
               grid.fields[self.Vfield.value]['data'][idx[:, 0], idx[:, 1],
                                                      idx[:, 2]],
               idx[:, 2], idx[:, 1], idx[:, 0])
        return aux

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 8
        self.YSIZE = 8
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])
        self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
        # self._update_axes()

    def _update_fig_ax(self):
        '''Set the figure and axis to plot.'''
        if self.plot_type in ("gridX", "gridY"):
            self.YSIZE = 5
        else:
            self.YSIZE = 8
        xwidth = 0.7
        yheight = 0.7
        self.ax.set_position([0.15, 0.15, xwidth, yheight])
        self.cax.set_position([0.15+xwidth, 0.15, 0.02, yheight])
        self._update_axes()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 7, 6)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''

        if self.Vgrid.value is None:
            return

        # Create the plot with PyArt GridMapDisplay
        self.ax.cla()  # Clear the plot axes
        self.cax.cla()  # Clear the colorbar axes

        if self.Vfield.value not in self.Vgrid.value.fields.keys():
            self.canvas.draw()
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(255,0,0,255);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.showMessage("Field not Found in Radar", msecs=5000)
            return
        else:
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(0,0,0,0);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.clearMessage()

        title = self.title
        limits = self.Vlims.value
        cmap = self.Vcmap.value

        self.display = pyart.graph.GridMapDisplay(self.Vgrid.value)
        # Create Plot
        if self.plot_type == "gridZ":
            self.display.plot_basemap(
                self.lat_lines, self.lon_lines, ax=self.ax)
            self.basemap = self.display.get_basemap()
            self.plot = self.display.plot_grid(
                self.Vfield.value, self.VlevelZ.value, vmin=cmap['vmin'],
                vmax=cmap['vmax'], cmap=cmap['cmap'], colorbar_flag=False,
                title=title, ax=self.ax, fig=self.fig)
        elif self.plot_type == "gridY":
            self.basemap = None
            self.plot = self.display.plot_latitudinal_level(
                self.Vfield.value, self.VlevelY.value, vmin=cmap['vmin'],
                vmax=cmap['vmax'], cmap=cmap['cmap'], colorbar_flag=False,
                title=title, ax=self.ax, fig=self.fig)
        elif self.plot_type == "gridX":
            self.basemap = None
            self.plot = self.display.plot_longitudinal_level(
                self.Vfield.value, self.VlevelX.value, vmin=cmap['vmin'],
                vmax=cmap['vmax'], cmap=cmap['cmap'], colorbar_flag=False,
                title=title, ax=self.ax, fig=self.fig)

        limits = self.Vlims.value
        x = self.ax.get_xlim()
        y = self.ax.get_ylim()
        limits['xmin'] = x[0]
        limits['xmax'] = x[1]
        limits['ymin'] = y[0]
        limits['ymax'] = y[1]

        self._update_axes()
        norm = mlabNormalize(vmin=cmap['vmin'],
                             vmax=cmap['vmax'])
        self.cbar = mlabColorbarBase(self.cax, cmap=cmap['cmap'],
                                     norm=norm, orientation='vertical')
        self.cbar.set_label(self.units)

        if self.plot_type == "gridZ":
            print("Plotting %s field, Z level %d in %s" % (
                self.Vfield.value, self.VlevelZ.value+1, self.name))
        elif self.plot_type == "gridY":
            print("Plotting %s field, Y level %d in %s" % (
                self.Vfield.value, self.VlevelY.value+1, self.name))
        elif self.plot_type == "gridX":
            print("Plotting %s field, X level %d in %s" % (
                self.Vfield.value, self.VlevelX.value+1, self.name))

        self.canvas.draw()

    def _update_axes(self):
        '''Change the Plot Axes.'''
        limits = self.Vlims.value
        self.ax.set_xlim(limits['xmin'], limits['xmax'])
        self.ax.set_ylim(limits['ymin'], limits['ymax'])
        self.ax.figure.canvas.draw()

    #########################
    # Check methods #
    #########################

    def _set_default_limits(self, strong=True):
        '''Set limits to pre-defined default.'''
        limits = self.Vlims.value
        if limits is None:
            limits = {}
        if self.Vgrid.value is None:
            limits['xmin'] = 0
            limits['xmax'] = 1
            limits['ymin'] = 0
            limits['ymax'] = 1
        elif self.plot_type == "gridZ":
            if self.basemap is not None:
                limits['xmin'] = self.basemap.llcrnrx
                limits['xmax'] = self.basemap.urcrnrx
                limits['ymin'] = self.basemap.llcrnry
                limits['ymax'] = self.basemap.urcrnry
            else:
                limits['xmin'] = -150
                limits['xmax'] = 150
                limits['ymin'] = -150
                limits['ymax'] = 150
        elif self.plot_type == "gridY":
            limits['xmin'] = (self.Vgrid.value.axes['x_disp']['data'][0] /
                              1000.)
            limits['xmax'] = (self.Vgrid.value.axes['x_disp']['data'][-1] /
                              1000.)
            limits['ymin'] = (self.Vgrid.value.axes['z_disp']['data'][0] /
                              1000.)
            limits['ymax'] = (self.Vgrid.value.axes['z_disp']['data'][-1] /
                              1000.)
        elif self.plot_type == "gridX":
            limits['xmin'] = (self.Vgrid.value.axes['y_disp']['data'][0] /
                              1000.)
            limits['xmax'] = (self.Vgrid.value.axes['y_disp']['data'][-1] /
                              1000.)
            limits['ymin'] = (self.Vgrid.value.axes['z_disp']['data'][0] /
                              1000.)
            limits['ymax'] = (self.Vgrid.value.axes['z_disp']['data'][-1] /
                              1000.)
        self.Vlims.change(limits, strong)

    def _set_default_cmap(self, strong=True):
        '''Set colormap to pre-defined default.'''
        cmap = pyart.config.get_field_colormap(self.Vfield.value)
        d = {}
        d['cmap'] = cmap
        lims = pyart.config.get_field_limits(self.Vfield.value,
                                             self.Vgrid.value)
        if lims != (None, None):
            d['vmin'] = lims[0]
            d['vmax'] = lims[1]
        else:
            d['vmin'] = -10
            d['vmax'] = 65
        self.Vcmap.change(d, strong)

    def _get_default_title(self):
        '''Get default title from pyart.'''
        if (
            self.Vgrid.value is None or
            self.Vfield.value not in self.Vgrid.value.fields):
            return ''
        if self.plot_type == "gridZ":
            return pyart.graph.common.generate_grid_title(self.Vgrid.value,
                                                          self.Vfield.value,
                                                          self.Vlevel.value)
        elif self.plot_type == "gridY":
            return pyart.graph.common.generate_latitudinal_level_title(
                self.Vgrid.value, self.Vfield.value, self.Vlevel.value)
        elif self.plot_type == "gridX":
            return pyart.graph.common.generate_longitudinal_level_title(
                self.Vgrid.value, self.Vfield.value, self.Vlevel.value)

    def _get_default_units(self):
        '''Get default units for current grid and field.'''
        if self.Vgrid.value is not None:
            try:
                return self.Vgrid.value.fields[self.Vfield.value]['units']
            except:
                return ''
        else:
            return ''

    def _check_file_type(self):
        '''Check file to see if the file type.'''
        # self._update_fig_ax()
        return

    def change_plot_type(self, plot_type):
        '''Change plot type.'''
        # remove shared variables
        for key in ("VlevelZ", "VlevelY", "VlevelX"):
            if key in self.sharedVariables.keys():
                del self.sharedVariables[key]
        if plot_type == "gridZ":
            self.sharedVariables["VlevelZ"] = self.NewLevel
        elif plot_type == "gridY":
            self.sharedVariables["VlevelY"] = self.NewLevel
        elif plot_type == "gridX":
            self.sharedVariables["VlevelX"] = self.NewLevel
        else:
            import warnings
            warnings.warn('Invalid Plot type %s, reseting to gridZ' %
                          plot_type)
            self.sharedVariables["VlevelZ"] = self.NewLevel
            plot_type = "gridZ"
        self.plot_type = plot_type

    ########################
    # Image save methods #
    ########################

    def _quick_savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display via PyArt interface.'''
        imagename = self.display.generate_filename(
            self.Vfield.value, self.Vlevel.value, ext=IMAGE_EXT)
        self.canvas.print_figure(os.path.join(os.getcwd(), imagename),
                                 dpi=DPI)
        self.statusbar.showMessage('Saved to %s' % os.path.join(os.getcwd(),
                                                                imagename))

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        imagename = self.display.generate_filename(
            self.Vfield.value, self.Vlevel.value, ext=IMAGE_EXT)
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', imagename, file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)

    ########################
    #      get methods     #
    ########################

    def getPlotAxis(self):
        ''' get :py:class:`matplotlib.axes.Axes` instance of main plot '''
        return self.ax

    def getStatusBar(self):
        ''' get :py:class:`PyQt4.QtGui.QStatusBar` instance'''
        return self.statusbar

    def getField(self):
        ''' get current field '''
        return self.Vfield.value

    def getUnits(self):
        ''' get current units '''
        return self.units

    ########################
    #      Properties      #
    ########################

    @property
    def Vlevel(self):
        '''Alias to VlevelZ, VlevelY or VlevelX depending on plot_type.'''
        if self.plot_type == "gridZ":
            return self.VlevelZ
        elif self.plot_type == "gridY":
            return self.VlevelY
        elif self.plot_type == "gridX":
            return self.VlevelX
        else:
            return None

    @property
    def levels(self):
        '''Values from the axes of grid, depending on plot_type.'''
        if self.plot_type == "gridZ":
            return self.Vgrid.value.axes['z_disp']['data'][:]
        elif self.plot_type == "gridY":
            return self.Vgrid.value.axes['y_disp']['data'][:]
        elif self.plot_type == "gridX":
            return self.Vgrid.value.axes['x_disp']['data'][:]
        else:
            return None
예제 #38
0
class Stock(QMainWindow):
    """ main Stock class """
    
    def __init__(self, parent=None):
        log(NAME, 'debug')
        
        QMainWindow.__init__(self, parent)
        self.comboBox = QComboBox()                
        self.setWindowTitle(NAME)        
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        self.plotColor = 'r'
        self.plotStyle = ''
        self.noOfFiles = 30    
        self.mDict = dict()
        self.getData()
        self.comboBox.addItems(sorted(self.mDict.keys()))                 
        self.on_draw()
        
        log('Initialized ' + str(self.noOfFiles) + ' files...')            
        
    def on_draw(self):
        comboChoose = self.comboBox.currentText()
        
        cashName, mtply, values = self.getCash(comboChoose)
                
        self.data = map(float, values)
        
        self.axes.clear()
        self.axes.grid(self.grid_cb.isChecked())
                    
        _y = self.data
        _x = range(len(self.data))
            
        self.axes.plot(_x, _y, self.plotColor + self.plotStyle, label=str(cashName))
        self.axes.legend()
                
        self.canvas.draw()

    def create_menu(self):      
        # ------------------ FILE MENU --------------------  
        self.file_menu = self.menuBar().addMenu("&File")

        load_file_action = self.create_action("&Save plot",
            shortcut="Ctrl+S", slot=self.save_plot, 
            tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close, 
            shortcut="Ctrl+Q", tip="Close the application")

        self.add_actions(self.file_menu, 
            (load_file_action, None, quit_action))
        # ------------------ PREFS MENU --------------------
        self.pref_menu = self.menuBar().addMenu('&Preferences')
        pref_action = self.create_action('&Options', 
            shortcut='Ctrl+O', slot = self.prefs,
            tip = 'Configure options') 
        self.add_actions(self.pref_menu, (pref_action,))

        # ------------------ HELP MENU --------------------
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About this application')

        self.add_actions(self.help_menu, (about_action,))

    def create_main_frame(self):
        self.main_frame = QWidget()
        
        # Create the mpl Figure and FigCanvas objects. 
        # 5x4 inches, 100 dots-per-inch
        #
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        
        # Since we have only one plot, we can use add_axes 
        # instead of add_subplot, but then the subplot
        # configuration tool in the navigation toolbar wouldn't
        # work.
        #
        self.axes = self.fig.add_subplot(111)
        
        # Bind the 'pick' event for clicking on one of the bars
        #
        self.canvas.mpl_connect('pick_event', self.on_pick)
        
        # Create the navigation toolbar, tied to the canvas
        #
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Other GUI controls
        # 
        self.connect(self.comboBox, SIGNAL('currentIndexChanged(const QString&)'), self.on_draw)
        
        self.draw_button = QPushButton("&Draw")
        self.connect(self.draw_button, SIGNAL('clicked()'), self.on_draw)
        
        self.grid_cb = QCheckBox("Show &Grid")
        self.grid_cb.setChecked(False)
        self.connect(self.grid_cb, SIGNAL('stateChanged(int)'), self.on_draw)
                
        #
        # Layout with box sizers
        # 
        hbox = QHBoxLayout()
        
        for w in [  self.comboBox, self.draw_button, self.grid_cb]:
            hbox.addWidget(w)
            hbox.setAlignment(w, Qt.AlignVCenter)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
    
    def create_status_bar(self):
        self.status_text = QLabel(NAME)
        self.statusBar().addWidget(self.status_text, 1)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action
    
    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        
        path = unicode(QFileDialog.getSaveFileName(self, 
                        'Save file', '', 
                        file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)

    def prefs(self):            
        self.statusBar().showMessage('Preferences')
        
        #
        # Pass the parent - self (the calling form) to the dialog
        # to take advantage of the fact that by default PyQt centers a dialog over
        # its parent and also because the dialogs that have a parent do not get a 
        # separate entry in the taskbar.
        #
        dialog = PropertitesDlg(self)
        #
        # Mark current color as selected
        #
        for k,v in PropertitesDlg.COLORS.items():
            if v == self.plotColor:
                _colorStr = k
                break
        _indexC = dialog.colorComboBox.findText(_colorStr)
        if _indexC != -1:
            dialog.colorComboBox.setCurrentIndex(_indexC)

        #
        # Mark current line style as selected
        #
        for k,v in PropertitesDlg.STYLES.items():
            if v == self.plotStyle:
                _styleStr = k
                break
        _indexS = dialog.styleComboBox.findText(_styleStr)
        if _indexS != -1:
            dialog.styleComboBox.setCurrentIndex(_indexS)
                        #
        # Open a properties dumb dialog and grab results 
        #
        if dialog.exec_():            
            self.plotColor = PropertitesDlg.COLORS.get(str(dialog.colorComboBox.currentText()))        
            self.plotStyle = PropertitesDlg.STYLES.get(str(dialog.styleComboBox.currentText()))
            self.on_draw()
                
    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)
                
    def on_pick(self, event):
        # The event received here is of the type
        # matplotlib.backend_bases.PickEvent
        #
        # It carries lots of information, of which we're using
        # only a small amount here.
        # 
        box_points = event.artist.get_bbox().get_points()
        msg = "You've clicked on a bar with coords:\n %s" % box_points
        
        QMessageBox.information(self, "Click!", msg)
        
    def on_about(self):
        msg = '\n' + NAME + '\n\n' + AUTHOR + '\n' + HISTORY + '\n'

        QMessageBox.about(self, "About", msg.strip())
                                            
    def getData(self):
        
        _mDict = dict()
        
        log('Retrieving XML data from nbp.pl...', 'debug')
        try:
            fList = urllib.urlopen('http://www.nbp.pl/kursy/xml/dir.txt')    
            lines = fList.readlines()
            aLines = [ a for a in lines if a.startswith('a') ] # list of files, which starts with 'a'
    
            for line in aLines[len(aLines) - self.noOfFiles:]:
                line = line.strip()
                log('Retrieving XML data from http://www.nbp.pl/kursy/xml/' + line + '.xml', 'debug')
                xmlFile = urllib.urlopen('http://www.nbp.pl/kursy/xml/' + line + '.xml')    
                xmlData = xml.dom.minidom.parse(xmlFile)
    
                nodeList = xmlData.getElementsByTagName('numer_tabeli')
                number = nodeList[0].childNodes[0].nodeValue
                log('Table number: ' + number, 'debug')
    
                nodeList = xmlData.getElementsByTagName('data_publikacji')
                data = nodeList[0].childNodes[0].nodeValue
                log('Date of publication: ' + data ,'debug')
    
                #cNodes = xmlData.childNodes        
    
                for i in xmlData.getElementsByTagName('pozycja'):
                    code = i.getElementsByTagName('kod_waluty')[0].childNodes[0].nodeValue
                    name = i.getElementsByTagName('nazwa_waluty')[0].childNodes[0].nodeValue.encode("iso-8859-15", "replace")
                    mtply = i.getElementsByTagName('przelicznik')[0].childNodes[0].nodeValue
                    value = i.getElementsByTagName('kurs_sredni')[0].childNodes[0].nodeValue.replace(',', '.')
                        
                    try:
                        _mDict[code].append(value)
                    except KeyError:                 
                        _mDict[code] = []            
                        _mDict[code].append(name)
                        _mDict[code].append(mtply)
                        _mDict[code].append(value)
                                                
            log(_mDict, 'debug')
        except Exception, err:
            log('Exception caught: ' + str(err))
            sys.exit(1)

        self.mDict = _mDict
예제 #39
0
class EsaEpixForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('ePix ESA Live Display')

        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()

        self.textbox.setText('1 2 3 4')
        self.on_draw()



    def on_about(self):
        msg = """ ESA ePix online display
        """
        QMessageBox.about(self, "About the app", msg.strip())


    def on_pick(self, event):
        # The event received here is of the type
        # matplotlib.backend_bases.PickEvent
        #
        # It carries lots of information, of which we're using
        # only a small amount here.
        # 
        box_points = event.artist.get_bbox().get_points()
        msg = "You've clicked on a bar with coords:\n %s" % box_points
        
        QMessageBox.information(self, "Click!", msg)



    def on_draw(self):
        """ Redraws the figure
        """
        str = unicode(self.textbox.text())
        self.data = map(int, str.split())
        
        x = range(len(self.data))

        # clear the axes and redraw the plot anew
        #
        self.axes.clear()        
        self.axes.grid(self.grid_cb.isChecked())
        
        self.axes.bar(
            left=x, 
            height=self.data, 
            width=self.slider.value() / 100.0, 
            align='center', 
            alpha=0.44,
            picker=5)
        
        self.canvas.draw()


    def create_menu(self):        

        self.file_menu = self.menuBar().addMenu("&File")
        
        load_file_action = self.create_action("&Save plot",
            shortcut="Ctrl+S", slot=self.save_plot, 
            tip="Save the plot")
        
        quit_action = self.create_action("&Quit",
            shortcut="Ctrl+Q", slot=self.close, 
            tip="Close the application")
        
        #self.add_actions(self.file_menu, 
        #    (load_file_action, None, quit_action))
        
        self.add_actions(self.file_menu, (quit_action,load_file_action))

        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About this thing')
        
        self.add_actions(self.help_menu, (about_action,))


    def create_main_frame(self):
        self.main_frame = QWidget()
        
        # Create the mpl Figure and FigCanvas objects. 
        # 5x4 inches, 100 dots-per-inch
        #
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        
        # Since we have only one plot, we can use add_axes 
        # instead of add_subplot, but then the subplot
        # configuration tool in the navigation toolbar wouldn't
        # work.
        #
        self.axes = self.fig.add_subplot(111)
        
        # Bind the 'pick' event for clicking on one of the bars
        #
        self.canvas.mpl_connect('pick_event', self.on_pick)
        
        # Create the navigation toolbar, tied to the canvas
        #
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Other GUI controls
        # 
        self.textbox = QLineEdit()
        self.textbox.setMinimumWidth(200)
        self.connect(self.textbox, SIGNAL('editingFinished ()'), self.on_draw)
        
        self.draw_button = QPushButton("&Draw")
        self.connect(self.draw_button, SIGNAL('clicked()'), self.on_draw)
        
        self.grid_cb = QCheckBox("Show &Grid")
        self.grid_cb.setChecked(False)
        self.connect(self.grid_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        
        slider_label = QLabel('Bar width (%):')
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(1, 100)
        self.slider.setValue(20)
        self.slider.setTracking(True)
        self.slider.setTickPosition(QSlider.TicksBothSides)
        self.connect(self.slider, SIGNAL('valueChanged(int)'), self.on_draw)
        
        #
        # Layout with box sizers
        # 
        hbox = QHBoxLayout()
        
        for w in [  self.textbox, self.draw_button, self.grid_cb,
                    slider_label, self.slider]:
            hbox.addWidget(w)
            hbox.setAlignment(w, Qt.AlignVCenter)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)


    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        
        path = unicode(QFileDialog.getSaveFileName(self, 
                        'Save file', '', 
                        file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def create_status_bar(self):
        self.status_text = QLabel("This is a status text")
        self.statusBar().addWidget(self.status_text, 1)


    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action
예제 #40
0
파일: highTemplar.py 프로젝트: bmazin/SDR
class highTemplar(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        #print '1'
        self.setWindowTitle('High Templar Resonator Setup')
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        #print '2'
        #self.disableCommandButtons()
        
        self.numThreadsRunning=0
        self.currentChannel=[0,0,0,0,0,0,0,0]
        #self.roachStatus=[0,0,0,0,0,0,0,0]
        
        self.connected = 0
        self.roach0=Roach(0)
        self.roach1=Roach(1)
        self.roach2=Roach(2)
        self.roach3=Roach(3)
        self.roach4=Roach(4)
        self.roach5=Roach(5)
        self.roach6=Roach(6)
        self.roach7=Roach(7)
        self.roaches=[self.roach0,self.roach1,self.roach2,self.roach3,self.roach4,self.roach5,self.roach6,self.roach7]
        
        #print '3' 

        self.showControls()
        self.threadPool=[]
        for roach in self.roaches:
            self.threadPool.append(RoachThread(roach))
            pass
        for thread in self.threadPool:
            self.connect(thread,QtCore.SIGNAL("connectedRoach(int)"),self.catchRoachConnectionSignal)
            self.connect(thread,QtCore.SIGNAL("loadedFrequency(int)"),self.catchRoachThreadSignal)
            self.connect(thread,QtCore.SIGNAL("loadedLUT(int)"),self.catchRoachThreadSignal)
            self.connect(thread,QtCore.SIGNAL("swept(int)"),self.catchRoachThreadSignal)
            self.connect(thread,QtCore.SIGNAL("rotated(int)"),self.catchRoachThreadSignal)
            self.connect(thread,QtCore.SIGNAL("centered(int)"),self.catchRoachThreadSignal)
            self.connect(thread,QtCore.SIGNAL("loadedFIR(int)"),self.catchRoachThreadSignal)
            self.connect(thread,QtCore.SIGNAL("loadedThreshold(int)"),self.catchRoachThreadSignal)


            thread.setTerminationEnabled(False)
        self.status_text.setText('Connecting Roaches...')
        QTimer.singleShot(0, self.startThreads)

    def startThreads(self):
        for thread in self.threadPool:
            thread.start()
            #thread.running()
        #    self.emit(QtCore.SIGNAL("startThread()"))
        #for roach in self.roaches:
        #    roach.startThread()

    def catchRoachConnectionSignal(self,roachNum):
        self.connected+=1
        self.colorCommandButtons(roach=[roachNum],color='red')
        self.roaches[roachNum].setStatus(1)
        #print 'here 1'
        #for roach in self.roaches:
        #    if roach.getState() == RoachState.connect:
        #        connected+=1
        #        #print 'roach',roach.getNum()
        #        self.colorCommandButtons(roach=[int(roach.getNum())],color='red')
        if self.connected == len(self.roaches):
            print '...Done connecting roaches'
            #print 'l:', len(self.commandButtons)
            self.colorCommandButtons(roach=[len(self.commandButtons)-1],color='blue')
            self.status_text.setText('All Roaches Connected')

    def catchRoachThreadSignal(self,roachNum):
        #print 'here:',roachNum
        if self.roaches[roachNum].getError() == 0:
                
            self.colorCommandButtons(roach=[roachNum],command=[self.roaches[roachNum].getState()],color='green')
            self.status_text.setText('Roach: '+str(roachNum)+' command: '+ RoachState.parseState(self.roaches[roachNum].getState())+' completed')
            self.roaches[roachNum].setStatus(1)
        else:
            print 'Error on roach',roachNum,':',self.roaches[roachNum].getError()
            self.colorCommandButtons(roach=[roachNum],command=[self.roaches[roachNum].getNextState()],color='error')
            self.roaches[roachNum].emptyCommandQueue()
            self.roaches[roachNum].setStatus(1)
            self.roaches[roachNum].resetError()
 

    def catchRoachLoadFreqSignal(self,s):
        print 's:',s

        self.numThreadsRunning-=1
        if self.numThreadsRunning == 0:
            self.threadPool=[]
            self.enableCommandButtons()
            if self.checkRoachErrors(RoachState.loadFreq)==0:
                print 'roaches finished loading freq file!'
                self.status_text.setText('roaches finished loading freq file')
            else:
                #errors!
                pass

    def commandButtonClicked(self):
        source = self.sender()
        print 'Roach: ',source.roach,'Command: ',RoachState.parseState(source.command)
        for i in source.roach:
            if self.roaches[i].hasCommand():
                print 'Roach still working...'
            else: 
                self.commandRoach(i,self.roaches[i].getState(),source.command)

            #print 'command ready', i, source.command



        #if source.command == 'loadFreq':
        #    self.disableCommandButtons()
        #    self.status_text.setText('Loading Frequency Files for Roach:'+str(source.roach))
        #    print 'Loading Frequency Files for Roach:',str(source.roach)
        #    #This is where the GUI grabs the freqFile and gives it to the roaches
        #    #freqFile=self.label_freqFile_0.text()
        #    #roach0.setFreqFile(freqFile)

        #    #print 'nums:',source.roach
        #    self.status=0
        #    for i in source.roach:
        #        #print 'i:',i
        #        self.threadPool.append(RoachThread(self.roaches[i],RoachState.loadFreq))
        #        self.connect(self.threadPool[len(self.threadPool)-1],QtCore.SIGNAL("loadedFrequency()"),self.catchRoachLoadFreqSignal)
        #        self.threadPool[len(self.threadPool)-1].start()
        #        self.numThreadsRunning+=1
        #else:
        #    print 'No such command',source.command, 'from roach',source.roach

    def commandRoach(self,roachNum,state,command):
        """State Machine"""

        #do everything between current state and new state
        for com in range(state+1,command):
            self.roaches[roachNum].pushCommand(com)
            self.colorCommandButtons(roach=[roachNum],command=[com],color='cyan')
            print 'pushed',RoachState.parseState(com)
        self.roaches[roachNum].pushCommand(command)
        self.colorCommandButtons(roach=[roachNum],command=[command],color='cyan')
        print 'pushed',RoachState.parseState(command)
        for com in range(command+1,RoachState.loadThreshold+1):
            self.colorCommandButtons(roach=[roachNum],command=[com],color='red')



        #if command == RoachState.loadFreq:
        #    self.roaches[roachNum].pushCommand(RoachState.loadFreq)
            
        #elif command == RoachState.defineLUT:
        #    if self.roaches[roachNum].getState() == RoachState.connect:
        #        self.roaches[roachNum].pushCommand(RoachState.loadFreq)
        #    self.roaches[roachNum].pushCommand(RoachState.defineLUT)
        #elif command == RoachState.sweep:
        #    if self.roaches[roachNum].getState() == RoachState.connect:
        #        self.roaches[roachNum].pushCommand(RoachState.loadFreq)
        #        self.roaches[roachNum].pushCommand(RoachState.defineLUT)
        #    elif self.roaches[roachNum].getState() == RoachState.loadFreq:
        #        self.roaches[roachNum].pushCommand(RoachState.defineLUT)
        #    self.roaches[roachNum].pushCommand(RoachState.sweep)

        #elif command == RoachState.rotate:
        #    pass
        #elif command == RoachState.center:
        #    pass
        #elif command == RoachState.loadFIR:
        #    pass
        #elif command == RoachState.loadThreshold:
        #    pass
        #else:
        #    print 'no code iplemented yet'
        #    self.roaches[roachNum].setError(9)
        #self.roaches[roachNum].setStatus(1)

    def checkRoachErrors(self,command):
        errors=0
        for roach in self.roaches:
            if roach.getState == command and roach.getStatus==0:
                print 'roach',roach.getNum,'failed command',command
                errors+=1
                roach.setStatus(1)
        return errors

    def radioRoachChanged(self):
        source=self.sender()

        if source.isChecked():
            #time.sleep(.1)
            #self.showControls(source.roach)
            pass
        else:       #signal from the radio roach that was turned off
            self.saveControls(source.roach)

    def showControls(self):
        """change plot, resonator characteristics etc"""
        #print 'showing'
        roachNum=-1
        for radio in self.radioRoaches:
            if radio.isChecked():
                roachNum = radio.roach
        #print 'changing',roachNum
        roach=self.roaches[int(roachNum)]
        self.textbox_loFreq.setText('%e'%roach.getLoFreq())
        self.textbox_freqFile.setText(str(roach.getFreqFile()))
        self.textbox_saveDir.setText(str(roach.getSaveDir()))
        self.textbox_loSpan.setText('%e'%float(roach.getLoSpan()))
        self.textbox_inputAtten.setText(str(roach.getInputAtten()))
        self.textbox_startAtten.setText(str(roach.getStartAtten()))
        self.textbox_stopAtten.setText(str(roach.getStopAtten()))
        self.textbox_ddsSyncLag.setText(str(roach.getDdsSyncLag()))
        #print 'done'

    def saveControls(self,roachNum):
        """save current resonator characteristics etc"""
        roach=self.roaches[int(roachNum)]
        roach.setLoFreq(float(self.textbox_loFreq.text()))
        roach.setFreqFile(self.textbox_freqFile.text())
        roach.setSaveDir(self.textbox_saveDir.text())
        roach.setLoSpan(float(self.textbox_loSpan.text()))
        roach.setInputAtten(int(self.textbox_inputAtten.text()))
        roach.setStartAtten(int(self.textbox_startAtten.text()))
        roach.setStopAtten(int(self.textbox_stopAtten.text()))
        roach.setDdsSyncLag(int(self.textbox_ddsSyncLag.text()))
        #print 'saved',roachNum
        self.showControls()
        

    def deleteResonator(self):
        print 'delete resonator'

    def updateResonator(self):
        print 'update resonator'
        self.roaches[0].pushCommand(RoachState.loadFreq)
        #self.roaches[0].pushCommand(RoachState.defineLUT)



    def colorCommandButtons(self,roach=[0,1,2,3,4,5,6,7,8],command=[RoachState.loadFreq,RoachState.defineLUT,RoachState.sweep,RoachState.rotate,RoachState.center,RoachState.loadFIR,RoachState.loadThreshold],color='red'):
        for roachNum in roach:
            for com in command:
                if color == 'red':
                    self.commandButtons[roachNum][com-1].setEnabled(True)
                    self.commandButtons[roachNum][com-1].setPalette(self.redButtonPalette)
                if color == 'green':
                    self.commandButtons[roachNum][com-1].setEnabled(True)
                    self.commandButtons[roachNum][com-1].setPalette(self.greenButtonPalette)
                if color == 'blue':
                    self.commandButtons[roachNum][com-1].setEnabled(True)
                    self.commandButtons[roachNum][com-1].setPalette(self.blueButtonPalette)
                if color == 'gray':
                    self.commandButtons[roachNum][com-1].setEnabled(False)
                    self.commandButtons[roachNum][com-1].setPalette(self.grayButtonPalette)
                if color == 'error':
                    self.commandButtons[roachNum][com-1].setEnabled(True)
                    self.commandButtons[roachNum][com-1].setPalette(self.errorButtonPalette)
                if color == 'cyan':
                    self.commandButtons[roachNum][com-1].setEnabled(True)
                    self.commandButtons[roachNum][com-1].setPalette(self.cyanButtonPalette)



#    def disableCommandButtons(self):
#        for arr in self.commandButtons:
#            for button in arr:
#                button.setEnabled(False)
#                button.setPalette(self.grayButtonPalette)

#    def enableCommandButtons(self,roach=[0,1,2,3,4,5,6,7,8],command=[RoachState.loadFreq,RoachState.defineLUT,RoachState.sweep,RoachState.rotate,RoachState.center,RoachState.loadFIR,RoachState.loadThreshold],color='red'):
#        for roachNum in roach:
#            for com in command:
#                self.commandButtons[roachNum][com-1].setEnabled(True)
#                if color == 'red':
#                    self.commandButtons[roachNum][com-1].setPalette(self.redButtonPalette)
#                if color == 'green':
#                    self.commandButtons[roachNum][com-1].setPalette(self.greenButtonPalette)
                
#    def finishedCommandButtons(self,roach=[0,1,2,3,4,5,6,7,8],command=[RoachState.loadFreq,RoachState.defineLUT,RoachState.sweep,RoachState.rotate,RoachState.center,RoachState.loadFIR,RoachState.loadThreshold],color='red'):
#        for roachNum in roach:
#            for com in command:
#                self.commandButtons[roachNum][com-1].setEnabled(True)
#                if color == 'red':
#                    self.commandButtons[roachNum][com-1].setPalette(self.redButtonPalette)
#                if color == 'green':
#                    self.commandButtons[roachNum][com-1].setPalette(self.greenButtonPalette)



        #for arr in self.commandButtons:
        #    for button in arr:
        #        button.setEnabled(True)
        #        button.setPalette(self.redButtonPalette)

    def create_main_frame(self):
        self.main_frame = QWidget()

        # Create the mpl Figure and FigCanvas objects. 
        self.dpi = 100
        self.fig = Figure((9.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        self.axes0 = self.fig.add_subplot(121)
        self.axes1 = self.fig.add_subplot(122)

        #cid=self.canvas.mpl_connect('button_press_event', self.changeCenter)
        
        # Create the navigation toolbar, tied to the canvas
        #self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        self.mpl_toolbar = customNavToolBar(self.canvas,self.main_frame)
        
        #button color palettes        
        self.greenButtonPalette = QPalette()
        self.greenButtonPalette.setColor(QPalette.Button,Qt.green)
        self.redButtonPalette = QPalette()
        self.redButtonPalette.setColor(QPalette.Button,Qt.darkRed)
        self.grayButtonPalette = QPalette()
        self.grayButtonPalette.setColor(QPalette.Button,Qt.gray)
        self.blueButtonPalette = QPalette()
        self.blueButtonPalette.setColor(QPalette.Button,Qt.blue)
        self.errorButtonPalette = QPalette()
        self.errorButtonPalette.setColor(QPalette.Button,Qt.red)
        self.cyanButtonPalette = QPalette()
        self.cyanButtonPalette.setColor(QPalette.Button,Qt.darkCyan)

        #Command Labels:
        self.label_loadFreq = QLabel('Load Freq/Atten:')
        self.label_defineLUT = QLabel("Define LUT's:")
        self.label_sweep = QLabel('Sweep:')
        self.label_rotate = QLabel('Rotate Loops:')
        self.label_center = QLabel('Center Loops:')
        self.label_loadFIR = QLabel("Load FIR's:")
        self.label_loadThreshold = QLabel('Load Thresholds:')
        self.commandLabels=[self.label_loadFreq,self.label_defineLUT,self.label_sweep,self.label_rotate,self.label_center,self.label_loadFIR,self.label_loadThreshold]
        for label in self.commandLabels:
            label.setMaximumWidth(110)
            label.setMinimumWidth(110)

        #Roach Labels
        self.label_roachNum = QLabel('Roach:')
        self.label_roach0 = QLabel('roach 0')
        self.label_roach1 = QLabel('roach 1')
        self.label_roach2 = QLabel('roach 2')
        self.label_roach3 = QLabel('roach 3')
        self.label_roach4 = QLabel('roach 4')
        self.label_roach5 = QLabel('roach 5')
        self.label_roach6 = QLabel('roach 6')
        self.label_roach7 = QLabel('roach 7')
        self.label_allRoaches = QLabel('All')
        self.roachLabels=[self.label_roachNum,self.label_roach0,self.label_roach1,self.label_roach2,self.label_roach3,self.label_roach4,self.label_roach5,self.label_roach6,self.label_roach7,self.label_allRoaches]
        for label in self.roachLabels[1:]:
            label.setMaximumWidth(50)
            label.setMinimumWidth(50)
        self.label_roachNum.setMaximumWidth(110)
        self.label_roachNum.setMinimumWidth(110)

        #Roach 0 command buttons
        self.button_loadFreq_0 = QPushButton()
        self.button_defineLUT_0 = QPushButton()
        self.button_sweep_0 = QPushButton()
        self.button_rotate_0 = QPushButton()
        self.button_center_0 = QPushButton()
        self.button_loadFIR_0 = QPushButton()
        self.button_loadThreshold_0 = QPushButton()
        roach0CommandButtons =[self.button_loadFreq_0,self.button_defineLUT_0,self.button_sweep_0,self.button_rotate_0,self.button_center_0,self.button_loadFIR_0,self.button_loadThreshold_0]
        
        #Roach 1 command buttons
        self.button_loadFreq_1 = QPushButton()
        self.button_defineLUT_1 = QPushButton()
        self.button_sweep_1 = QPushButton()
        self.button_rotate_1 = QPushButton()
        self.button_center_1 = QPushButton()
        self.button_loadFIR_1 = QPushButton()
        self.button_loadThreshold_1 = QPushButton()
        roach1CommandButtons =[self.button_loadFreq_1,self.button_defineLUT_1,self.button_sweep_1,self.button_rotate_1,self.button_center_1,self.button_loadFIR_1,self.button_loadThreshold_1]

        #Roach 2 command buttons
        self.button_loadFreq_2 = QPushButton()
        self.button_defineLUT_2 = QPushButton()
        self.button_sweep_2 = QPushButton()
        self.button_rotate_2 = QPushButton()
        self.button_center_2 = QPushButton()
        self.button_loadFIR_2 = QPushButton()
        self.button_loadThreshold_2 = QPushButton()
        roach2CommandButtons =[self.button_loadFreq_2,self.button_defineLUT_2,self.button_sweep_2,self.button_rotate_2,self.button_center_2,self.button_loadFIR_2,self.button_loadThreshold_2]

        #Roach 3 command buttons
        self.button_loadFreq_3 = QPushButton()
        self.button_defineLUT_3 = QPushButton()
        self.button_sweep_3 = QPushButton()
        self.button_rotate_3 = QPushButton()
        self.button_center_3 = QPushButton()
        self.button_loadFIR_3 = QPushButton()
        self.button_loadThreshold_3 = QPushButton()
        roach3CommandButtons =[self.button_loadFreq_3,self.button_defineLUT_3,self.button_sweep_3,self.button_rotate_3,self.button_center_3,self.button_loadFIR_3,self.button_loadThreshold_3]

        #Roach 4 command buttons
        self.button_loadFreq_4 = QPushButton()
        self.button_defineLUT_4 = QPushButton()
        self.button_sweep_4 = QPushButton()
        self.button_rotate_4 = QPushButton()
        self.button_center_4 = QPushButton()
        self.button_loadFIR_4 = QPushButton()
        self.button_loadThreshold_4 = QPushButton()
        roach4CommandButtons =[self.button_loadFreq_4,self.button_defineLUT_4,self.button_sweep_4,self.button_rotate_4,self.button_center_4,self.button_loadFIR_4,self.button_loadThreshold_4]

        #Roach 5 command buttons
        self.button_loadFreq_5 = QPushButton()
        self.button_defineLUT_5 = QPushButton()
        self.button_sweep_5 = QPushButton()
        self.button_rotate_5 = QPushButton()
        self.button_center_5 = QPushButton()
        self.button_loadFIR_5 = QPushButton()
        self.button_loadThreshold_5 = QPushButton()
        roach5CommandButtons =[self.button_loadFreq_5,self.button_defineLUT_5,self.button_sweep_5,self.button_rotate_5,self.button_center_5,self.button_loadFIR_5,self.button_loadThreshold_5]

        #Roach 6 command buttons
        self.button_loadFreq_6 = QPushButton()
        self.button_defineLUT_6 = QPushButton()
        self.button_sweep_6 = QPushButton()
        self.button_rotate_6 = QPushButton()
        self.button_center_6 = QPushButton()
        self.button_loadFIR_6 = QPushButton()
        self.button_loadThreshold_6 = QPushButton()
        roach6CommandButtons =[self.button_loadFreq_6,self.button_defineLUT_6,self.button_sweep_6,self.button_rotate_6,self.button_center_6,self.button_loadFIR_6,self.button_loadThreshold_6]

        #Roach 7 command buttons
        self.button_loadFreq_7 = QPushButton()
        self.button_defineLUT_7 = QPushButton()
        self.button_sweep_7 = QPushButton()
        self.button_rotate_7 = QPushButton()
        self.button_center_7 = QPushButton()
        self.button_loadFIR_7 = QPushButton()
        self.button_loadThreshold_7 = QPushButton()
        roach7CommandButtons =[self.button_loadFreq_7,self.button_defineLUT_7,self.button_sweep_7,self.button_rotate_7,self.button_center_7,self.button_loadFIR_7,self.button_loadThreshold_7]

        #all Roaches command buttons
        self.button_loadFreq = QPushButton()
        self.button_defineLUT = QPushButton()
        self.button_sweep = QPushButton()
        self.button_rotate = QPushButton()
        self.button_center = QPushButton()
        self.button_loadFIR = QPushButton()
        self.button_loadThreshold = QPushButton()
        roachCommandButtons =[self.button_loadFreq,self.button_defineLUT,self.button_sweep,self.button_rotate,self.button_center,self.button_loadFIR,self.button_loadThreshold]

        #Matrix of roach command buttons
        self.commandButtons=[roach0CommandButtons,roach1CommandButtons,roach2CommandButtons,roach3CommandButtons,roach4CommandButtons,roach5CommandButtons,roach6CommandButtons,roach7CommandButtons,roachCommandButtons]

        for i in range(len(self.commandLabels)):
            
            for j in range(len(self.commandButtons)):
                self.commandButtons[j][i].setMaximumWidth(50)
                self.commandButtons[j][i].setMaximumHeight(50)
                self.commandButtons[j][i].setMinimumHeight(50)
                self.commandButtons[j][i].setEnabled(False)
                self.commandButtons[j][i].setMinimumWidth(50)
                self.commandButtons[j][i].setPalette(self.grayButtonPalette)
                self.commandButtons[j][i].roach = [j]
                if j==len(self.commandButtons)-1:
                    self.commandButtons[j][i].roach = [0,1,2,3,4,5,6,7]        #button forall roaches
                self.connect(self.commandButtons[j][i],SIGNAL('clicked()'),self.commandButtonClicked)
                if i==0:
                    self.commandButtons[j][i].command = RoachState.loadFreq
                if i==1:
                    self.commandButtons[j][i].command = RoachState.defineLUT
                if i==2:
                    self.commandButtons[j][i].command = RoachState.sweep
                if i==3:
                    self.commandButtons[j][i].command = RoachState.rotate
                if i==4:
                    self.commandButtons[j][i].command = RoachState.center
                if i==5:
                    self.commandButtons[j][i].command = RoachState.loadFIR
                if i==6:
                    self.commandButtons[j][i].command = RoachState.loadThreshold


        #Roach radio buttons
        self.radio_roach_0 = QRadioButton('Roach 0')
        self.radio_roach_0.setChecked(True)
        self.radio_roach_1 = QRadioButton('Roach 1')
        self.radio_roach_2 = QRadioButton('Roach 2')
        self.radio_roach_3 = QRadioButton('Roach 3')
        self.radio_roach_4 = QRadioButton('Roach 4')
        self.radio_roach_5 = QRadioButton('Roach 5')
        self.radio_roach_6 = QRadioButton('Roach 6')
        self.radio_roach_7 = QRadioButton('Roach 7')
        self.radioRoaches = [self.radio_roach_0,self.radio_roach_1,self.radio_roach_2,self.radio_roach_3,self.radio_roach_4,self.radio_roach_5,self.radio_roach_6,self.radio_roach_7]
        for i in range(len(self.radioRoaches)):
            self.connect(self.radioRoaches[i],SIGNAL('toggled(bool)'),self.radioRoachChanged)
            self.radioRoaches[i].roach=i
        

        #Channel Characteristics labels and textboxes
        self.label_channel = QLabel('CH: ')
        self.textbox_channel = QLineEdit('0')
        #atten spinbox, freq textbox, submit button
        self.spinbox_attenuation = QSpinBox()
        self.spinbox_attenuation.setMaximum(MAX_ATTEN)
        self.label_attenuation = QLabel('Atten:')
        self.textbox_freq = QLineEdit('0')
        self.textbox_freq.setMaximumWidth(130)
        self.label_freq = QLabel('Freq (GHz):')
        #median textbox, threshold textbox, submit button
        self.textbox_med = QLineEdit('0.0')
        self.textbox_med.setMaximumWidth(130)
        self.label_med = QLabel('median:')
        self.textbox_threshold = QLineEdit('0.0')
        self.textbox_threshold.setMaximumWidth(130)
        self.label_threshold = QLabel('threshold:')
        #update resonator button, remove resonator button
        self.button_deleteResonator = QPushButton('Remove Resonator')
        self.button_deleteResonator.setMaximumWidth(170)
        self.connect(self.button_deleteResonator, SIGNAL('clicked()'), self.deleteResonator)
        self.button_updateResonator = QPushButton("Update Resonator")
        self.button_updateResonator.setMaximumWidth(170)
        self.connect(self.button_updateResonator, SIGNAL('clicked()'), self.updateResonator)


        #Roach Properties
        self.label_freqFile = QLabel('Freq/Atten file:')
        self.label_freqFile.setMaximumWidth(100)
        self.textbox_freqFile = QLineEdit('ps_freq0.txt')
        self.textbox_freqFile.setMaximumWidth(200)
        self.label_saveDir = QLabel('Save Dir:')
        self.label_saveDir.setMaximumWidth(100)
        self.textbox_saveDir = QLineEdit('/home/sean/data/')
        self.textbox_saveDir.setMaximumWidth(200)
        self.label_loFreq = QLabel('LO Freq:')
        self.label_loFreq.setMaximumWidth(100)
        self.textbox_loFreq = QLineEdit('0')
        self.textbox_loFreq.setMaximumWidth(100)
        self.label_ddsSyncLag = QLabel('DDS Sync Lag:')
        self.label_ddsSyncLag.setMaximumWidth(100)
        self.textbox_ddsSyncLag = QLineEdit('151')
        self.textbox_ddsSyncLag.setMaximumWidth(100)
        self.label_inputAtten = QLabel('Input Atten:')
        self.label_inputAtten.setMaximumWidth(100)
        self.textbox_inputAtten = QLineEdit('5')
        self.textbox_inputAtten.setMaximumWidth(100)
        self.label_startAtten = QLabel('Start Atten:')
        self.label_startAtten.setMaximumWidth(100)
        self.textbox_startAtten = QLineEdit('10')
        self.textbox_startAtten.setMaximumWidth(100)
        self.label_stopAtten = QLabel('Stop Atten:')
        self.label_stopAtten.setMaximumWidth(100)
        self.textbox_stopAtten = QLineEdit('10')
        self.textbox_stopAtten.setMaximumWidth(100)
        self.label_loSpan = QLabel('LO Span:')
        self.label_loSpan.setMaximumWidth(100)
        self.textbox_loSpan = QLineEdit('0.5e9')
        self.textbox_loSpan.setMaximumWidth(100)

        
        
        #command buttons/labels
        vbox0=QVBoxLayout(spacing = 10)    #change spacing until looks good
        hbox00=QHBoxLayout(spacing=10)
        for label in self.roachLabels:
            hbox00.addWidget(label)
        vbox0.addLayout(hbox00)
        hbox01=QHBoxLayout(spacing=35)
        hbox02=QHBoxLayout(spacing=35)
        hbox03=QHBoxLayout(spacing=35)
        hbox04=QHBoxLayout(spacing=35)
        hbox05=QHBoxLayout(spacing=35)
        hbox06=QHBoxLayout(spacing=35)
        hbox07=QHBoxLayout(spacing=35)
        hbox08=QHBoxLayout(spacing=35)
        hboxes=[hbox01,hbox02,hbox03,hbox04,hbox05,hbox06,hbox07,hbox08]
        for i in range(len(self.commandLabels)):
            hboxes[i].addWidget(self.commandLabels[i])
            for j in range(len(self.commandButtons)):
                hboxes[i].addWidget(self.commandButtons[j][i])
            vbox0.addLayout(hboxes[i])

        #radio buttons
        vbox1 = QVBoxLayout()
        hbox10 = QHBoxLayout()
        for i in range(len(self.radioRoaches)/2+int(len(self.radioRoaches))%2):
            hbox10.addWidget(self.radioRoaches[i])
        hbox11 = QHBoxLayout()
        for i in range(len(self.radioRoaches)/2):
            hbox11.addWidget(self.radioRoaches[i+len(self.radioRoaches)/2+int(len(self.radioRoaches))%2])
        vbox1.addLayout(hbox10)
        vbox1.addLayout(hbox11)

        #figures
        vbox1.addWidget(self.canvas)
        vbox1.addWidget(self.mpl_toolbar)

        #channel characteristics
        hbox12=QHBoxLayout()
        hbox12.addWidget(self.label_channel)
        hbox12.addWidget(self.textbox_channel)
        hbox12.addWidget(self.button_updateResonator)
        hbox12.addWidget(self.button_deleteResonator)
        vbox1.addLayout(hbox12)
        hbox13 = QHBoxLayout()
        hbox13.addWidget(self.label_attenuation)
        hbox13.addWidget(self.spinbox_attenuation)  
        hbox13.addWidget(self.label_freq)
        hbox13.addWidget(self.textbox_freq)
        hbox13.addWidget(self.label_med)      
        hbox13.addWidget(self.textbox_med)
        hbox13.addWidget(self.label_threshold)
        hbox13.addWidget(self.textbox_threshold)
        vbox1.addLayout(hbox13)


        #roach properties
        hbox14=QHBoxLayout()
        hbox14.addWidget(self.label_loFreq)
        hbox14.addWidget(self.textbox_loFreq)
        hbox14.addWidget(self.label_freqFile)
        hbox14.addWidget(self.textbox_freqFile)
        hbox14.addWidget(self.label_saveDir)
        hbox14.addWidget(self.textbox_saveDir)
        vbox1.addLayout(hbox14)
        hbox15=QHBoxLayout()
        hbox15.addWidget(self.label_loSpan)
        hbox15.addWidget(self.textbox_loSpan)
        hbox15.addWidget(self.label_inputAtten)
        hbox15.addWidget(self.textbox_inputAtten)
        hbox15.addWidget(self.label_startAtten)
        hbox15.addWidget(self.textbox_startAtten)
        hbox15.addWidget(self.label_stopAtten)
        hbox15.addWidget(self.textbox_stopAtten)
        vbox1.addLayout(hbox15)
        hbox16=QHBoxLayout()
        hbox16.addWidget(self.label_ddsSyncLag)
        hbox16.addWidget(self.textbox_ddsSyncLag)
        vbox1.addLayout(hbox16)



        hbox = QHBoxLayout()
        hbox.addLayout(vbox0)
        hbox.addLayout(vbox1)
        
        vbox = QVBoxLayout()
        vbox.addLayout(hbox)

        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)

    def create_status_bar(self):
        self.status_text = QLabel("Awaiting orders.")
        self.statusBar().addWidget(self.status_text, 1)

    def create_menu(self):        
        self.file_menu = self.menuBar().addMenu("&File")
        
        load_file_action = self.create_action("&Save plot",shortcut="Ctrl+S",slot=self.save_plot, tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close,shortcut="Ctrl+Q", tip="Close the application")
        
        self.add_actions(self.file_menu, (load_file_action, None, quit_action))
        
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", shortcut='F1',slot=self.on_about, tip='About the demo')
        
        self.add_actions(self.help_menu, (about_action,))

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        
        path = unicode(QFileDialog.getSaveFileName(self, 
                        'Save file', '', 
                        file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)

    def on_about(self):
        msg = """ Message to user goes here.
        """
        QMessageBox.about(self, "MKID-ROACH software demo", msg.strip())

    def closeEvent(self, event):
        for roach in self.roaches:
            roach.closeThread(1)
        #time.sleep(1)
        #for thread in self.threadPool:
            #thread.setTerminationEnabled(True)
            #thread.closeThread()
        time.sleep(.1)
        QtCore.QCoreApplication.instance().quit
예제 #41
0
class AppForm(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('Templar_noise')
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        self.dacStatus = 'off'
        self.dramStatus = 'off'
        self.tapStatus = 'off'
        self.socketStatus = 'off'
        self.ch_all = []
        self.attens = numpy.array([1. for i in range(256)])
        self.freqRes = 7812.5
        self.sampleRate = 512e6
        self.iq_centers = numpy.array([0.+0j]*256)
        
    def openClient(self):
        self.roach = corr.katcp_wrapper.FpgaClient(self.textbox_roachIP.text(),7147)
        time.sleep(2)
        self.status_text.setText('connection established')
        self.button_openClient.setDisabled(True)

    def programRFswitches(self, regStr = '10110'):
        #    5 bit word: LO_int/ext, RF_loop, LO_source(doubler), BB_loop, Ck_int/ext
        #regStr = self.textbox_rfSwReg.text()
        print int(regStr[0]), int(regStr[1]), int(regStr[2]),int(regStr[3]), int(regStr[4])
                
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 1)
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[0])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[0])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[0])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[1])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[1])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[1])<<2)+(0<<1)+(0<<0))                
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[2])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[2])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[2])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[3])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[3])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[3])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[4])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[4])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(int(regStr[4])<<2)+(0<<1)+(0<<0))   

        # Now clock out the data written to the reg.
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))   
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))                        
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(1<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 0)
        
    def programAttenuators(self, atten_in_desired, atten_out_desired):
        #    There are eight settings for each attenuator:
        #    0db, -0.5, -1, -2, -4, -8, -16, and -31.5, which
        #    are listed in order in "attenuations."    
        #atten_in_desired = float(self.textbox_atten_in.text())
        atten_in = 63 - int(atten_in_desired*2)
        
        #atten_out_desired = float(self.textbox_atten_out.text())
        if atten_out_desired <= 31.5:
            atten_out0 = 63
            atten_out1 = 63 - int(atten_out_desired*2)
        else:
            atten_out0 = 63 - int((atten_out_desired-31.5)*2)
            atten_out1 = 0
        """
        self.roach.write_int('SER_DI', (atten_in<<26)+(atten_out0<<20)+(atten_out1<<14))
        self.roach.write_int('SWAT_LE', 1)
        self.roach.write_int('start', 1)
        self.roach.write_int('start', 0)
        self.roach.write_int('SWAT_LE', 0)
        self.status_text.setText('Attenuators programmed. ')
        """
        reg = numpy.binary_repr((atten_in<<12)+(atten_out0<<6)+(atten_out1<<0))
        b = '0'*(18-len(reg)) + reg
        print reg, len(reg)
        self.roach.write_int('regs', (0<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 1)
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[0])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[0])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[0])<<2)+(0<<1)+(0<<0))

        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[1])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[1])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[1])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[2])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[2])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[2])<<2)+(0<<1)+(0<<0))

        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[3])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[3])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[3])<<2)+(0<<1)+(0<<0))

        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[4])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[4])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[4])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[5])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[5])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[5])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[6])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[6])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[6])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[7])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[7])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[7])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[8])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[8])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[8])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[9])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[9])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[9])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[10])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[10])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[10])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[11])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[11])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[11])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[12])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[12])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[12])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[13])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[13])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[13])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[14])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[14])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[14])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[15])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[15])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[15])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[16])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[16])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[16])<<2)+(0<<1)+(0<<0))
        
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[17])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[17])<<2)+(1<<1)+(0<<0))
        self.roach.write_int('regs', (0<<4)+(1<<3)+(int(b[17])<<2)+(0<<1)+(0<<0))
        self.roach.write_int('regs', (1<<4)+(1<<3)+(0<<2)+(0<<1)+(0<<0))
        self.roach.write_int('if_switch', 0)
        
    def programLO(self, freq=3.2e9, sweep_freq=0):
        f_pfd = 10e6
        if sweep_freq:
            f = freq
        else:
            f = float(self.textbox_loFreq.text())
        if f >= 4.4e9:
            f = f/2
            
        INT = int(f)/int(f_pfd)
        MOD = 2000
        FRAC = int(round(MOD*(f/f_pfd-INT)))
        if FRAC != 0:
            gcd = fractions.gcd(MOD,FRAC)
            if gcd != 1:
                MOD = MOD/gcd
                FRAC = int(FRAC/gcd)
        PHASE = 1
        R = 1
        power = 3
        aux_power = 3
        MUX = 3
        LOCK_DETECT = 1
        reg5 = (LOCK_DETECT<<22) + (1<<2) + (1<<0)
        reg4 = (1<<23) + (1<<18) + (1<<16) + (1<<8) + (aux_power<<6) + (1<<5) + (power<<3) + (1<<2)
        reg3 = (1<<10) + (1<<7) + (1<<5) + (1<<4) + (1<<1) + (1<<0)
        reg2 = (MUX<<26) + (R<<14) + (1<<11) + (1<<10) + (1<<9) + (1<<7) + (1<<6) + (1<<1)
        reg1 = (1<<27) + (PHASE<<15) + (MOD<<3) + (1<<0)
        reg0 = (INT<<15) + (FRAC<<3)
        
        regs = [reg5, reg4, reg3, reg2, reg1, reg0]
        
        for r in regs:
            self.roach.write_int('SER_DI', r)
            self.roach.write_int('LO_SLE', 1)
            self.roach.write_int('start', 1)
            self.roach.write_int('start', 0)
            self.roach.write_int('LO_SLE', 0)
        self.status_text.setText('LO programmed. ')

    def freqCombLUT(self, echo, freq, sampleRate, resolution, amplitude=[1.]*256, phase=[0.]*256, random_phase = 'yes'):
        offset = int(self.textbox_offset.text())
        amp_full_scale = 2**15-1
        N_freqs = len(freq)
        size = int(sampleRate/resolution)
        I, Q = numpy.array([0.]*size), numpy.array([0.]*size)
        single_I, single_Q = numpy.array([0.]*size), numpy.array([0.]*size)
        
        #numpy.random.seed(1000)
        for n in range(N_freqs):
            if random_phase == 'yes':
                phase[n] = numpy.random.uniform(0, 2*numpy.pi)
                
            x = [2*numpy.pi*freq[n]*(t+offset)/sampleRate+phase[n] for t in range(size)]
            y = [2*numpy.pi*freq[n]*t/sampleRate+phase[n] for t in range(size)]

            single_I = amplitude[n]*numpy.cos(x)
            single_Q = amplitude[n]*numpy.sin(y)
            
            I = I + single_I
            Q = Q + single_Q
        
        a = numpy.array([abs(I).max(), abs(Q).max()])
        I = numpy.array([int(i*amp_full_scale/a.max()) for i in I])
        Q = numpy.array([int(q*amp_full_scale/a.max()) for q in Q])
        if echo == 'yes':
            print 'scale factor: ', a.max()
            self.scale_factor = a.max()
            print 'Set atten_out to: ', 20*numpy.log10(self.previous_scale_factor/self.scale_factor) + self.minimumAttenuation
        return I, Q
        
    def define_DAC_LUT(self):
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + 512e6
        self.freqs_dac = [round((f-f_base)/self.freqRes)*self.freqRes for f in freqs]
        atten_min = self.attens.min()
        print "minimum attenuation: ", self.minimumAttenuation
        amplitudes = [10**(+(atten_min-a)/20.) for a in self.attens]
        self.I_dac, self.Q_dac = self.freqCombLUT('yes', self.freqs_dac, self.sampleRate, self.freqRes, amplitudes)
        self.status_text.setText('done defining DAC freqs. ')

    def defne_noiseRO(self, freq=10e6):
		sampleRate = 512e6
		size = int(512e6/7812.5)

		start_x = 2*numpy.pi*freq/sampleRate
		end_x = 2*numpy.pi*freq*size/sampleRate
		x = numpy.linspace(start_x, end_x, size)
		start_y = 0
		end_y = 0 + 2*numpy.pi*freq*(size)/sampleRate
		y = numpy.linspace(start_y, end_y, size)
		
		I = numpy.cos(x)
		Q = numpy.sin(y)
	
		sigma = 10.
		iq = numpy.array([0+0j]*size)
		for i in range(size):
			I[i] = I[i] + random.gauss(0, sigma)
			Q[i] = Q[i] + random.gauss(0, sigma)

		amp_full_scale = 2**15-1
		a = numpy.array([abs(I).max(), abs(Q).max()])
		I = numpy.array([int(i*amp_full_scale/a.max()) for i in I])
		Q = numpy.array([int(q*amp_full_scale/a.max()) for q in Q])

		return I, Q
	
    def noiseRO(self):
		freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
		f_base = float(self.textbox_loFreq.text())
		for n in range(len(freqs)):
			if freqs[n] < f_base:
				freqs[n] = freqs[n] + 512e6
		self.freqs_dac = [round((f-f_base)/self.freqRes)*self.freqRes for f in freqs]
		atten_min = self.attens.min()
		amplitudes = [10**(+(atten_min-a)/20.) for a in self.attens]
		self.I_dac, self.Q_dac = self.define_noiseRO(self.freqs_dac[0])
		self.status_text.setText('done defining noise RO. ')
		
    def define_DDS_LUT(self, phase = [0.]*256):
        ch_shift = 147  # This number should be verified in the utility ddc2x_v*.py
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + 512e6

        freqs_dds = [0 for j in range(256)]
        for n in range(len(freqs)):
            freqs_dds[n] = round((freqs[n]-f_base)/self.freqRes)*self.freqRes

        freq_residuals = self.select_bins(freqs_dds)

        L = int(self.sampleRate/self.freqRes)
        self.I_dds, self.Q_dds = [0.]*L, [0.]*L
        for m in range(256):
            I, Q = self.freqCombLUT('no', [freq_residuals[m]], 2e6, self.freqRes, [1.], [phase[m]], 'no')
            for j in range(len(I)/2):
                self.I_dds[j*512+2*((m+ch_shift)%256)] = I[2*j]
                self.I_dds[j*512+2*((m+ch_shift)%256)+1] = I[2*j+1]
                self.Q_dds[j*512+2*((m+ch_shift)%256)] = Q[2*j]
                self.Q_dds[j*512+2*((m+ch_shift)%256)+1] = Q[2*j+1]

        self.axes0.clear()
        self.axes0.plot(self.I_dds, '.', self.Q_dds, '.')
        self.canvas.draw()
        print "done defing dds freqs. "

    def select_bins(self, readout_freqs):
        fft_len = 2**9
        bins = ''
        i = 0
        residuals = []
        for f in readout_freqs:
            fft_bin = int(round(f*fft_len/self.sampleRate))
            fft_freq = fft_bin*self.sampleRate/fft_len
            freq_residual = round((f - fft_freq)/self.freqRes)*self.freqRes
            residuals.append(freq_residual)
            bins = bins + struct.pack('>l', fft_bin)
            self.roach.write_int('bins', fft_bin)
            self.roach.write_int('load_bins', (i<<1) + (1<<0))
            self.roach.write_int('load_bins', (i<<1) + (0<<0))
            i = i + 1
        self.status_text.setText('done writing LUTs. ')
        return residuals
    
    def write_LUTs(self):
        if self.dacStatus == 'off':
            self.roach.write_int('startDAC', 0)
        else:
            self.toggleDAC()
            
        binaryData = ''
        print len(self.I_dac)
        for n in range(len(self.I_dac)/2):
            i_dac_0 = struct.pack('>h', self.I_dac[2*n])
            i_dac_1 = struct.pack('>h', self.I_dac[2*n+1])
            i_dds_0 = struct.pack('>h', self.I_dds[2*n])
            i_dds_1 = struct.pack('>h', self.I_dds[2*n+1])
            q_dac_0 = struct.pack('>h', self.Q_dac[2*n])
            q_dac_1 = struct.pack('>h', self.Q_dac[2*n+1])
            q_dds_0 = struct.pack('>h', self.Q_dds[2*n])
            q_dds_1 = struct.pack('>h', self.Q_dds[2*n+1])
            binaryData = binaryData + q_dds_1 + q_dds_0 + q_dac_1 + q_dac_0 + i_dds_1 + i_dds_0 + i_dac_1 + i_dac_0
        self.roach.write('dram_memory', binaryData)
        
        # Write LUTs to file.
        saveDir = str(self.textbox_saveDir.text())
        f = open(saveDir + 'luts.dat', 'w')
        f.write(binaryData)
        f.close()

    def loadIQcenters(self):
        saveDir = str(self.textbox_saveDir.text())
        #saveDir = str(os.environ['PWD'] + '/'+ self.textbox_saveDir.text())
        centers_for_file = [[0., 0.]]*256
        for ch in range(256):
            I_c = int(self.iq_centers[ch].real/2**3)
            Q_c = int(self.iq_centers[ch].imag/2**3)

            center = (I_c<<16) + (Q_c<<0)
            self.roach.write_int('conv_phase_centers', center)
            self.roach.write_int('conv_phase_load_centers', (ch<<1)+(1<<0))
            self.roach.write_int('conv_phase_load_centers', 0)
        
            centers_for_file[ch] = [self.iq_centers[ch].real, self.iq_centers[ch].imag]
            
        numpy.savetxt(saveDir+'centers.dat', centers_for_file)

    def findIQcenters(self, I, Q):
        I_0 = (I.max()+I.min())/2.
        Q_0 = (Q.max()+Q.min())/2.
                
        return complex(I_0, Q_0)
  
    def rotateLoops(self):
		print "Calculating loop rotations..."
		L = 2**15
		bin_data_phase = ''
		self.roach.write_int('startSnap', 0)
		self.roach.write_int('snapI_ctrl', 1)
		self.roach.write_int('snapI_ctrl', 0)
		self.roach.write_int('snapQ_ctrl', 1)
		self.roach.write_int('snapQ_ctrl', 0)
		self.roach.write_int('startSnap', 1)
		time.sleep(0.1)
		bin_data_I = self.roach.read('snapI_bram', 4*L)
		bin_data_Q = self.roach.read('snapQ_bram', 4*L)
		I = numpy.array([0]*L)
		Q = numpy.array([0]*L)
		for m in range(L):
			I[m] = struct.unpack('>l', bin_data_I[m*4:m*4+4])[0]/2**14 - self.iq_centers[0].real
			Q[m] = struct.unpack('>l', bin_data_Q[m*4:m*4+4])[0]/2**14 - self.iq_centers[1].imag

		phase = [0.]*256
		phase[0] = numpy.arctan2(Q.mean(), I.mean())
        
		self.define_DDS_LUT(phase)
		self.write_LUTs()
		print "done."

    """            
    def sweepLO(self):
		atten_in = float(self.textbox_atten_in.text())
		saveDir = str(self.textbox_saveDir.text())
		savefile = saveDir + 'ps_' + time.strftime("%Y%m%d-%H%M%S",time.localtime()) + '.h5'
		dac_freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
		self.N_freqs = len(dac_freqs)
		f_base = float(self.textbox_loFreq.text())

		if f_base >= 4.4e9:
			self.programRFswitches('10010')
			print 'LO doubled.'
		else:
			#self.programRFswitches('10100')
			self.programRFswitches('10110')
			print 'LO normal operation.'
		loSpan = float(self.textbox_loSpan.text())
		# spanShift = 0.5 --> a sweep centered on the resonant freq.
		spanShift = float(self.textbox_spanShift.text())
		df = 1e4
		steps = int(loSpan/df)
		print "LO steps: ", steps
		# Frequency span is off-center to account for freq. shift to higher values for atten -> inf.
		lo_freqs = [f_base+i*df-spanShift*steps*df for i in range(steps)]

		atten_start = int(self.textbox_powerSweepStart.text())
		atten_stop = int(self.textbox_powerSweepStop.text())
		attens = [i for i in range(atten_start, atten_stop+1)]
        
        self.roach.write_int('ch_we0', 1)
        self.roach.write_int('ch_we1', 1)
		
        for a in attens:	
			print a
			self.programAttenuators(atten_in, a)
			time.sleep(0.5)
			f_span = []
			l = 0
			self.f_span = [[0]*steps]*self.N_freqs
			for f in dac_freqs:
				f_span = f_span + [f-spanShift*steps*df+n*df for n in range(steps)]
				self.f_span[l] = [f-spanShift*steps*df+n*df for n in range(steps)]
				l = l + 1
			I = numpy.zeros(self.N_freqs*steps, dtype='float32')
			Q = numpy.zeros(self.N_freqs*steps, dtype='float32')

			self.I, self.Q = numpy.array([[0.]*steps]*self.N_freqs),numpy.array([[0.]*steps]*self.N_freqs)
			for i in range(steps):
				self.programLO(lo_freqs[i],1)
				L = 2**15
				bin_data_phase = ''
				self.roach.write_int('startSnap', 0)
				self.roach.write_int('snapI_ctrl', 1)
				self.roach.write_int('snapI_ctrl', 0)
				self.roach.write_int('snapQ_ctrl', 1)
				self.roach.write_int('snapQ_ctrl', 0)
				self.roach.write_int('startSnap', 1)
				time.sleep(0.1)
				bin_data_I = self.roach.read('snapI_bram', 4*L)
				bin_data_Q = self.roach.read('snapQ_bram', 4*L)
				I = numpy.array([0]*L)
				Q = numpy.array([0]*L)
				for m in range(L):
					I[m] = struct.unpack('>l', bin_data_I[m*4:m*4+4])[0]/2**14
					Q[m] = struct.unpack('>l', bin_data_Q[m*4:m*4+4])[0]/2**14
				self.I[0,i] = I.mean()
				self.Q[0,i] = Q.mean()

			self.programLO(f_base,1)
            
            # Find IQ centers.
			self.I_on_res, self.Q_on_res = [0.]*self.N_freqs, [0.]*self.N_freqs
			bin_data_phase = ''
			self.roach.write_int('startSnap', 0)
			self.roach.write_int('snapI_ctrl', 1)
			self.roach.write_int('snapI_ctrl', 0)
			self.roach.write_int('snapQ_ctrl', 1)
			self.roach.write_int('snapQ_ctrl', 0)
			self.roach.write_int('startSnap', 1)
			time.sleep(0.1)
			bin_data_I = self.roach.read('snapI_bram', 4*L)
			bin_data_Q = self.roach.read('snapQ_bram', 4*L)
			I = numpy.array([0]*L)
			Q = numpy.array([0]*L)
			for m in range(L):
				I[m] = struct.unpack('>l', bin_data_I[m*4:m*4+4])[0]/2**14
				Q[m] = struct.unpack('>l', bin_data_Q[m*4:m*4+4])[0]/2**14
			self.I_on_res[0] = I.mean()
			self.Q_on_res[0] = Q.mean()
			self.iq_centers[0] = self.findIQcenters(self.I[0,:],self.Q[0,:])

			N = steps*self.N_freqs

		self.axes0.clear()
		self.axes1.clear()
		self.axes0.semilogy((self.I[0,:]**2 + self.Q[0,:]**2)**.5, '.-')
        #self.axes0.semilogy(f_span, (self.I[0,:]**2 + self.Q[0,:]**2)**.5, '.-')
        #self.axes0.semilogy(f_span, (I**2 + Q**2)**.5, '.-')
		self.axes1.plot(self.I[0,:], self.Q[0,:], '.-', self.iq_centers.real[0:self.N_freqs], self.iq_centers.imag[0:self.N_freqs], '.', self.I_on_res, self.Q_on_res, '.')
		#self.axes1.plot(f_span[0:N-1], dist, '.-')
		#self.axes1.set_xlim((-100000,100000))
		#self.axes1.set_ylim((-100000,100000))
		self.canvas.draw()
    """

    def sweepLO(self):
        atten_in = float(self.textbox_atten_in.text())
        saveDir = str(self.textbox_saveDir.text())
        #saveDir = str(os.environ['PWD'] + '/'+ self.textbox_saveDir.text())
        savefile = saveDir + 'ps_' + time.strftime("%Y%m%d-%H%M%S",time.localtime()) + '.h5'
        dac_freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        self.N_freqs = len(dac_freqs)
        f_base = float(self.textbox_loFreq.text())
        
        if f_base >= 4.4e9:
            self.programRFswitches('10010')
            print 'LO doubled.'
        else:
            #self.programRFswitches('10100')
            self.programRFswitches('10110')
            print 'LO normal operation.'
        loSpan = float(self.textbox_loSpan.text())
        # spanShift = 0.5 --> a sweep centered on the resonant freq.
        spanShift = float(self.textbox_spanShift.text())
        df = 1e4
        steps = int(loSpan/df)
        print "LO steps: ", steps
        # Frequency span is off-center to account for freq. shift to higher values for atten -> inf.
        lo_freqs = [f_base+i*df-spanShift*steps*df for i in range(steps)]
        
        atten_start = int(self.textbox_powerSweepStart.text())
        atten_stop = int(self.textbox_powerSweepStop.text())
        attens = [i for i in range(atten_start, atten_stop+1)]

        for a in attens:    
            print a
            self.programAttenuators(atten_in, a)
            time.sleep(0.5)
            f_span = []
            l = 0
            self.f_span = [[0]*steps]*self.N_freqs
            for f in dac_freqs:
                f_span = f_span + [f-spanShift*steps*df+n*df for n in range(steps)]
                self.f_span[l] = [f-spanShift*steps*df+n*df for n in range(steps)]
                l = l + 1
            I = numpy.zeros(self.N_freqs*steps, dtype='float32')
            Q = numpy.zeros(self.N_freqs*steps, dtype='float32')
            I_std = numpy.zeros(self.N_freqs*steps, dtype='float32')
            Q_std = numpy.zeros(self.N_freqs*steps, dtype='float32')

            self.I, self.Q = numpy.array([[0.]*steps]*self.N_freqs),numpy.array([[0.]*steps]*self.N_freqs)
            for i in range(steps):
                #print i
                self.programLO(lo_freqs[i],1)
                self.roach.write_int('startAccumulator', 0)
                self.roach.write_int('avgIQ_ctrl', 1)
                self.roach.write_int('avgIQ_ctrl', 0)
                self.roach.write_int('startAccumulator', 1)
                time.sleep(0.001)
                data = self.roach.read('avgIQ_bram', 4*2*256)
                for j in range(self.N_freqs):
                    I[j*steps+i] = struct.unpack('>l', data[4*j:4*j+4])[0]
                    Q[j*steps+i] = struct.unpack('>l', data[4*(j+256):4*(j+256)+4])[0]
                    I_std[j*steps+i] = 0
                    Q_std[j*steps+i] = 0
                    self.I[j, i] = I[j*steps+i]
                    self.Q[j, i] = Q[j*steps+i]
            self.programLO(f_base,1)
            
            # Find IQ centers.
            self.I_on_res, self.Q_on_res = [0.]*self.N_freqs, [0.]*self.N_freqs
            self.roach.write_int('startAccumulator', 0)
            self.roach.write_int('avgIQ_ctrl', 1)
            self.roach.write_int('avgIQ_ctrl', 0)
            self.roach.write_int('startAccumulator', 1)
            time.sleep(0.001)
            data = self.roach.read('avgIQ_bram', 4*2*256)
            for j in range(self.N_freqs):
                self.I_on_res[j] = struct.unpack('>l', data[4*j:4*j+4])[0]
                self.Q_on_res[j] = struct.unpack('>l', data[4*(j+256):4*(j+256)+4])[0]
                self.iq_centers[j] = self.findIQcenters(I[j*steps:j*steps+steps],Q[j*steps:j*steps+steps])
            
        numpy.savetxt('centers.dat', [self.iq_centers.real, self.iq_centers.imag])

        self.axes1.clear()
        self.axes0.semilogy(f_span, (I**2 + Q**2)**.5, '.-')
        self.axes1.plot(I, Q, '.-', self.iq_centers.real[0:self.N_freqs], self.iq_centers.imag[0:self.N_freqs], '.', self.I_on_res, self.Q_on_res, '.')
        self.canvas.draw()

    def toggleDAC(self):
        if self.dacStatus == 'off':
            print "Starting LUT...",
            self.roach.write_int('startDAC', 1)
            time.sleep(1)
            while self.roach.read_int('DRAM_LUT_rd_valid') != 0:
		print self.roach.read_int('DRAM_LUT_rd_valid')
                self.roach.write_int('startDAC', 0)
                time.sleep(0.35)
                self.roach.write_int('startDAC', 1)
                time.sleep(1)
                print ".",
            print "done."
            self.button_startDAC.setText('Stop DAC')
            self.dacStatus = 'on'
	    self.status_text.setText('DAC turned on. ')       
        else:
            self.roach.write_int('startDAC', 0)
            self.button_startDAC.setText('Start DAC')
            self.dacStatus = 'off'
	    self.status_text.setText('DAC turned off. ')       
   
    def loadFreqsAttens(self):
        f_base = float(self.textbox_loFreq.text())
        freqFile =str(self.textbox_freqFile.text())
        x = numpy.loadtxt(freqFile) 
        x_string = ''
        
        self.previous_scale_factor = x[0,0] 
        N_freqs = len(x[1:,0])
        for l in x[1:,0]:
            x_string = x_string + str(l*1e9) + '\n'
            
        self.iq_centers = numpy.array([0.+0j]*256)
        for n in range(N_freqs):
            #for n in range(256):
            self.iq_centers[n] = complex(x[n+1,1], x[n+1,2])
            
        self.attens = x[1:,3]
        self.minimumAttenuation = numpy.array(x[1:,3]).min()
        self.textedit_DACfreqs.setText(x_string)
        
    def loadLUTs(self):
        self.scale_factor = 1.
        self.iq_centers = numpy.array([0.+0j]*256)
        
        # Loads the DAC and DDS LUTs from file.  As well as the IQ loop centers.
        if self.dacStatus == 'off':
            self.roach.write_int('startDAC', 0)
        else:
            self.toggleDAC()

        saveDir = str(self.textbox_saveDir.text())
        #saveDir = str(os.environ['PWD'] + '/'+ self.textbox_saveDir.text())            
        f = open(saveDir+'luts.dat', 'r')
        binaryData = f.read()

        self.roach.write('dram_memory', binaryData)

        x = numpy.loadtxt(saveDir+'centers.dat')
        N_freqs = len(x[:,0])
        for n in range(N_freqs):
            self.iq_centers[n] = complex(x[n,0], x[n,1])
        
        #    Select and write bins for first stage of channelizer.
        freqs = map(float, unicode(self.textedit_DACfreqs.toPlainText()).split())
        f_base = float(self.textbox_loFreq.text())
        for n in range(len(freqs)):
            if freqs[n] < f_base:
                freqs[n] = freqs[n] + 512e6

        freqs_dds = [0 for j in range(256)]
        for n in range(len(freqs)):
            freqs_dds[n] = round((freqs[n]-f_base)/self.freqRes)*self.freqRes

        freq_residuals = self.select_bins(freqs_dds)
        
        print 'LUTs and IQ centers loaded from file.'

    def channelIncUp(self):
        ch = int(self.textbox_channel.text())
        ch = ch + 1
        ch = ch%self.N_freqs
        self.textbox_channel.setText(str(ch))
        self.axes0.clear()
        self.axes1.clear()
        self.axes0.semilogy(self.f_span[ch], (self.I[ch]**2 + self.Q[ch]**2)**.5, '.-')
        self.axes1.plot(self.I[ch], self.Q[ch], '.-', self.iq_centers.real[ch], self.iq_centers.imag[ch], '.', self.I_on_res[ch], self.Q_on_res[ch], '.')
	#self.axes1.set_xlim((-10000,10000))
    #self.axes1.set_ylim((-10000,10000))
	self.canvas.draw()
        
    def channelIncDown(self):
        ch = int(self.textbox_channel.text())
        ch = ch - 1
        ch = ch%self.N_freqs
        self.textbox_channel.setText(str(ch))
        self.axes0.clear()
        self.axes1.clear()
        self.axes0.semilogy(self.f_span[ch], (self.I[ch]**2 + self.Q[ch]**2)**.5, '.-')
        self.axes1.plot(self.I[ch], self.Q[ch], '.-', self.iq_centers.real[ch], self.iq_centers.imag[ch], '.', self.I_on_res[ch], self.Q_on_res[ch], '.')
        #self.axes1.set_xlim((-10000,10000))
        #self.axes1.set_ylim((-10000,10000))
        self.canvas.draw()

    def changeCenter(self, event):
        I = event.xdata
        Q = event.ydata
        #ch = int(self.textbox_channel.text())
        #print ch
        #self.iq_centers.real[ch] = I
        #self.iq_centers.imag[ch] = Q
        #self.axes1.plot(I, Q, '.')
        #self.canvas.draw()

    def snapshot(self):
        for r in range(self.N_freqs):
            self.roach.write_int('ch_we'+str(r), r)
            #self.roach.write_int('ch_we'+str(r), 1)
        for r in range(4-self.N_freqs):
            self.roach.write_int('ch_we'+str(r), 0)
            
        steps = int(self.textbox_noiseSteps.text())
        L = 2**15
        I, Q = [], []
        for n in range(steps):
            print n
            self.roach.write_int('startSnap', 0)
            self.roach.write_int('snapI_ctrl', 1)
            self.roach.write_int('snapI_ctrl', 0)
            self.roach.write_int('snapQ_ctrl', 1)
            self.roach.write_int('snapQ_ctrl', 0)
            self.roach.write_int('startSnap', 1)
            time.sleep(0.1)
            bin_data_I = self.roach.read('snapI_bram', 4*L)
            bin_data_Q = self.roach.read('snapQ_bram', 4*L)
            for m in range(L*2):#two 16 bit values in each 32-bit word
				#low order bits are an earlier value
                i = struct.unpack('>h', bin_data_I[m*2:m*2+2])[0]
                q = struct.unpack('>h', bin_data_Q[m*2:m*2+2])[0]
                I.append(i)
                Q.append(q)
        
        numpy.savetxt('test.dat', [I,Q])

        self.axes1.clear()
        self.axes1.plot(I,'.-',  Q, '.-')
        self.canvas.draw()

    def create_main_frame(self):
        self.main_frame = QWidget()
        
        # Create the mpl Figure and FigCanvas objects. 
        self.dpi = 100
        self.fig = Figure((9.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)
        self.axes0 = self.fig.add_subplot(121)
        #self.axes3 = self.axes0.twinx()
        self.axes1 = self.fig.add_subplot(122)
        
        cid=self.canvas.mpl_connect('button_press_event', self.changeCenter)
        
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        
        # Roach board's IP address
        self.textbox_roachIP = QLineEdit('10.0.0.14')
        self.textbox_roachIP.setMaximumWidth(200)
        label_roachIP = QLabel('Roach IP Address:')

        # Start connection to roach.
        self.button_openClient = QPushButton("&Open Client")
        self.button_openClient.setMaximumWidth(100)
        self.connect(self.button_openClient, SIGNAL('clicked()'), self.openClient)
        
        # LO frequency.
        self.textbox_loFreq = QLineEdit('5.07e9')
        self.textbox_loFreq.setMaximumWidth(100)
        label_loFreq = QLabel('LO frequency:')

        # Program LO.
        self.button_programLO = QPushButton("&Prog.")
        self.button_programLO.setMaximumWidth(100)
        self.connect(self.button_programLO, SIGNAL('clicked()'), self.programLO)
        label_programLO = QLabel('')

        # Sweep span
        self.textbox_loSpan = QLineEdit('0.5e6')
        self.textbox_loSpan.setMaximumWidth(50)
        label_loSpan = QLabel('LO Span')
        
        # Frequency span shift
        # A span shift of 0.75 shifts 75% of sweep span to the lower portion of the range.
        self.textbox_spanShift = QLineEdit('0.5')
        self.textbox_spanShift.setMaximumWidth(50)
        label_spanShift = QLabel('Span shift')
        
        # DAC Frequencies.
        self.textedit_DACfreqs = QTextEdit()
        self.textedit_DACfreqs.setMaximumWidth(170)
        self.textedit_DACfreqs.setMaximumHeight(100)
        label_DACfreqs = QLabel('DAC Freqs:')

        # Input attenuation.
        self.textbox_atten_in = QLineEdit('0')
        self.textbox_atten_in.setMaximumWidth(50)
        label_atten_in = QLabel('atten. (in)')

        # offset in lut
        self.textbox_offset = QLineEdit('0')
        self.textbox_offset.setMaximumWidth(50)

        # Power sweep range. 
        self.textbox_powerSweepStart = QLineEdit('16')
        self.textbox_powerSweepStart.setMaximumWidth(50)
        label_powerSweepStart = QLabel('Start Atten')
        self.textbox_powerSweepStop = QLineEdit('16')
        self.textbox_powerSweepStop.setMaximumWidth(50)
        label_powerSweepStop = QLabel('Stop Atten')

        # Save directory
        self.textbox_saveDir = QLineEdit('/home/sean/data/20111115/r0/')
        self.textbox_saveDir.setMaximumWidth(50)
        label_saveDir = QLabel('Save directory')
        label_saveDir.setMaximumWidth(150)
    
        # File with frequencies/attens
        self.textbox_freqFile = QLineEdit('freqs.txt')
        self.textbox_freqFile.setMaximumWidth(200)

        # Load freqs and attens from file.
        self.button_loadFreqsAttens = QPushButton("Load freqs/attens")
        self.button_loadFreqsAttens.setMaximumWidth(200)
        self.connect(self.button_loadFreqsAttens, SIGNAL('clicked()'), self.loadFreqsAttens)

        # Load freqs onto FPGA.
        self.button_write_LUTs = QPushButton("&Load LUTs")
        self.button_write_LUTs.setMaximumWidth(200)
        self.connect(self.button_write_LUTs, SIGNAL('clicked()'), self.write_LUTs)
      
        # Define noise readout.
        self.button_noiseRO = QPushButton("noise RO")
        self.button_noiseRO.setMaximumWidth(200)
        self.connect(self.button_noiseRO, SIGNAL('clicked()'), self.noiseRO)

        # Take snapshot.
        self.button_snapshot = QPushButton("Snapshot")
        self.button_snapshot.setMaximumWidth(200)
        self.connect(self.button_snapshot, SIGNAL('clicked()'), self.snapshot)
        
        # Noise data steps
        self.textbox_noiseSteps = QLineEdit('1')
        self.textbox_noiseSteps.setMaximumWidth(50)
        
		# Rotate IQ loops.
        self.button_rotateLoops = QPushButton("Rot. Loops")
        self.button_rotateLoops.setMaximumWidth(200)
        self.connect(self.button_rotateLoops, SIGNAL('clicked()'), self.rotateLoops)        

        # Translate IQ loops.
        self.button_translateLoops = QPushButton("Trans. Loops")
        self.button_translateLoops.setMaximumWidth(200)
        self.connect(self.button_translateLoops, SIGNAL('clicked()'), self.loadIQcenters)
        
        # DAC start button.
        self.button_startDAC = QPushButton("&Start DAC")
        self.button_startDAC.setMaximumWidth(200)
        self.connect(self.button_startDAC, SIGNAL('clicked()'), self.toggleDAC)

        # define DDS frequencies. 
        self.button_define_DDS_LUT= QPushButton("&Define DDS")
        self.button_define_DDS_LUT.setMaximumWidth(200)
        self.connect(self.button_define_DDS_LUT, SIGNAL('clicked()'), self.define_DDS_LUT)
        
        # define DAC frequencies. 
        self.button_define_DAC_LUT= QPushButton("&Define DAC LUT")
        self.button_define_DAC_LUT.setMaximumWidth(200)
        self.connect(self.button_define_DAC_LUT, SIGNAL('clicked()'), self.define_DAC_LUT)

        # Sweep LO
        self.button_sweepLO = QPushButton("Sweep LO")
        self.button_sweepLO.setMaximumWidth(340)
        self.connect(self.button_sweepLO, SIGNAL('clicked()'), self.sweepLO) 
        
        # load LUT and IQ centers from file
        self.button_loadLUTs = QPushButton("Load LUTs and centers")
        self.button_loadLUTs.setMaximumWidth(340)
        self.connect(self.button_loadLUTs, SIGNAL('clicked()'), self.loadLUTs)       
          
        # Channel increment up 1.
        self.button_channelIncUp = QPushButton("+")
        self.button_channelIncUp.setMaximumWidth(50)
        self.connect(self.button_channelIncUp, SIGNAL('clicked()'), self.channelIncUp)
        
        # Channel increment down 1.
        self.button_channelIncDown = QPushButton("-")
        self.button_channelIncDown.setMaximumWidth(50)
        self.connect(self.button_channelIncDown, SIGNAL('clicked()'), self.channelIncDown)
        
        # Channel to measure
        self.textbox_channel = QLineEdit('0')
        self.textbox_channel.setMaximumWidth(100)
        
        # Add widgets to window.
        gbox0 = QVBoxLayout()
        hbox01 = QHBoxLayout()
        hbox01.addWidget(self.textbox_roachIP)
        hbox01.addWidget(self.button_openClient)
        gbox0.addLayout(hbox01)
        gbox030 = QVBoxLayout()
        gbox030.addWidget(label_loFreq)
        gbox030.addWidget(self.textbox_loFreq)
        gbox032 = QVBoxLayout()
        gbox032.addWidget(label_programLO)
        gbox032.addWidget(self.button_programLO)
        gbox033 = QVBoxLayout()
        gbox033.addWidget(label_loSpan)
        gbox033.addWidget(self.textbox_loSpan)
        gbox034 = QVBoxLayout()
        gbox034.addWidget(label_spanShift)
        gbox034.addWidget(self.textbox_spanShift)
        gbox12 = QVBoxLayout()
        gbox12.addWidget(label_atten_in)
        gbox12.addWidget(self.textbox_atten_in)
        gbox10 = QVBoxLayout()
        gbox10.addWidget(label_powerSweepStart)
        gbox10.addWidget(self.textbox_powerSweepStart)
        gbox11 = QVBoxLayout()
        gbox11.addWidget(label_powerSweepStop)
        gbox11.addWidget(self.textbox_powerSweepStop)
        hbox11 = QHBoxLayout()
        hbox11.addLayout(gbox12)
        hbox11.addLayout(gbox10)
        hbox11.addLayout(gbox11)
        hbox11.addWidget(self.textbox_offset)
        hbox03 = QHBoxLayout()
        hbox03.addLayout(gbox030)
        hbox03.addLayout(gbox032)
        hbox03.addLayout(gbox033)
        hbox03.addLayout(gbox034)
        gbox0.addLayout(hbox03)
        gbox0.addLayout(hbox11)


        gbox1 = QVBoxLayout()
        gbox1.addWidget(label_DACfreqs)
        gbox1.addWidget(self.textedit_DACfreqs)
        hbox12 = QHBoxLayout()
        hbox12.addWidget(label_saveDir)
        hbox12.addWidget(self.textbox_saveDir)
        gbox1.addLayout(hbox12)
        hbox13 = QHBoxLayout()
        hbox13.addWidget(self.textbox_channel)
        hbox13.addWidget(self.button_channelIncDown)
        hbox13.addWidget(self.button_channelIncUp)
        gbox1.addLayout(hbox13)

        gbox2 = QVBoxLayout()
        hbox23 = QHBoxLayout()
        hbox23.addWidget(self.textbox_freqFile)
        hbox23.addWidget(self.button_loadFreqsAttens)
        gbox2.addLayout(hbox23)
        hbox20 = QHBoxLayout()
        hbox20.addWidget(self.button_define_DAC_LUT)
        hbox20.addWidget(self.button_define_DDS_LUT)
        gbox2.addLayout(hbox20)

        hbox25 = QHBoxLayout()
        hbox25.addWidget(self.button_noiseRO)
        hbox25.addWidget(self.textbox_noiseSteps)
        hbox25.addWidget(self.button_snapshot)
        gbox2.addLayout(hbox25)

        hbox24 = QHBoxLayout()
        hbox24.addWidget(self.button_write_LUTs)
        hbox24.addWidget(self.button_startDAC)
        gbox2.addLayout(hbox24)
        gbox2.addWidget(self.button_sweepLO)
        hbox22 = QHBoxLayout()
        hbox22.addWidget(self.button_rotateLoops)
        hbox22.addWidget(self.button_translateLoops)
        gbox2.addLayout(hbox22)
        gbox2.addWidget(self.button_loadLUTs)
        hbox = QHBoxLayout()
        hbox.addLayout(gbox0)
        hbox.addLayout(gbox1)     
        hbox.addLayout(gbox2)
        
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addLayout(hbox)
        
        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)
  
    def create_status_bar(self):
        self.status_text = QLabel("Awaiting orders.")
        self.statusBar().addWidget(self.status_text, 1)
        
    def create_menu(self):        
        self.file_menu = self.menuBar().addMenu("&File")
        
        load_file_action = self.create_action("&Save plot",
            shortcut="Ctrl+S", slot=self.save_plot, 
            tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close, 
            shortcut="Ctrl+Q", tip="Close the application")
        
        self.add_actions(self.file_menu, 
            (load_file_action, None, quit_action))
        
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About the demo')
        
        self.add_actions(self.help_menu, (about_action,))

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_plot(self):
        file_choices = "PNG (*.png)|*.png"
        
        path = unicode(QFileDialog.getSaveFileName(self, 
                        'Save file', '', 
                        file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def on_about(self):
        msg = """ Message to user goes here.
        """
        QMessageBox.about(self, "MKID-ROACH software demo", msg.strip())
예제 #42
0
class CutePlot(QMainWindow):
    def __init__(self, parent=None):
        super(CutePlot, self).__init__(parent)

        # Default values for lower and upper bound
        self.LB_default = -10
        self.UB_default = 10
        # Create main plot area + menus + status bar
        self.create_main_frame()
        #self.textbox.setText()
        self.LB_UB_defaults()
        self.on_draw()
        self.statusBar()
        self.setWindowTitle('Graficador')
        self.create_menu()
        self.guardarImagen()

    def LB_UB_defaults(self):
        # Set default values for lower bound and upper bound
        self.lowerbound.setText(str(self.LB_default))
        self.upperbound.setText(str(self.UB_default))

    def create_main_frame(self):
        self.main_frame = QWidget()
        # 7x5 inches, 80 dots-per-inch
        self.dpi = 80
        self.fig = Figure((5, 3), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)

        self.is_data = False

        self.axes = self.fig.add_subplot(111)

        # axis_state keeps track of how many subplots are present
        # axis_state = 0: main plot only
        # axis_state = 1: horizontal split (quadrants 1 and 2)
        # axis_state = 2: vertical split (quadrants 1 and 4)
        # axis_state = 3: show all 4 subplots
        self.axis_state = 0

        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)

        # f(x) textbox
        self.title = QLabel('<font size=4><em>f</em> (<em>x </em>) =</font>')
        self.textbox = QLineEdit()
        self.textbox.setMinimumWidth(200)
        self.connect(self.textbox, SIGNAL('returnPressed()'), self.on_draw)

        # Lowerbound and upperbound textboxes
        self.LB_title = QLabel('<font size=4>Min:</font>')
        self.lowerbound = QLineEdit()
        self.lowerbound.setMaximumWidth(30)
        self.connect(self.lowerbound, SIGNAL('returnPressed()'), self.on_draw)

        self.UB_title = QLabel('<font size=4>Max:</font>')
        self.upperbound = QLineEdit()
        self.upperbound.setMaximumWidth(30)
        self.connect(self.upperbound, SIGNAL('returnPressed()'), self.on_draw)

        # Plot button
        self.draw_button = QPushButton("&Plot")
        self.connect(self.draw_button, SIGNAL('clicked()'), self.on_draw)

        # Hold checkbox
        self.hold_cb = QCheckBox("&Hold")
        self.hold_cb.setChecked(False)
        self.connect(self.hold_cb, SIGNAL('stateChanged(int)'),
                     self.on_minor_change)
        self.hold_cb.setToolTip('Prevent new plots from replacing old ones')
        self.hold_cb.setStatusTip('Prevent new plots from replacing old ones')

        # Log-x and log-y checkboxes
        self.logx_cb = QCheckBox("Log-&x")
        self.logx_cb.setChecked(False)
        self.connect(self.logx_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        self.logx_cb.setToolTip('Change x-axis to logarithmic scale')
        self.logx_cb.setStatusTip('Change x-axis to logarithmic scale')

        self.logy_cb = QCheckBox("Log-&y")
        self.logy_cb.setChecked(False)
        self.connect(self.logy_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        self.logy_cb.setToolTip('Change y-axis to logarithmic scale')
        self.logy_cb.setStatusTip('Change y-axis to logarithmic scale')

        # Truncated-log checkbox
        self.trunc_cb = QCheckBox("Show &Negative")
        self.trunc_cb.setChecked(False)
        self.connect(self.trunc_cb, SIGNAL('stateChanged(int)'), self.on_draw)
        self.trunc_cb.setToolTip(
            'Plot negative values of log-transformed functions')
        self.trunc_cb.setStatusTip(
            'Plot negative values of log-transformed functions')

        # Grid checkbox
        self.grid_cb = QCheckBox("&Grid")
        self.grid_cb.setChecked(False)
        self.connect(self.grid_cb, SIGNAL('stateChanged(int)'),
                     self.on_minor_change)
        self.grid_cb.setToolTip('Show grid')
        self.grid_cb.setStatusTip('Show grid')

        # Grid layout
        grid = QGridLayout()
        grid.setSpacing(10)

        gridCol = 0
        for w in [
                self.title, self.textbox, self.LB_title, self.lowerbound,
                self.UB_title, self.upperbound, self.draw_button
        ]:
            grid.addWidget(w, 0, gridCol)
            gridCol += 1

        grid2 = QGridLayout()
        grid2.setSpacing(10)
        gridCol = 0
        for w in [
                self.logx_cb, self.logy_cb, self.trunc_cb, self.hold_cb,
                self.grid_cb
        ]:
            grid2.addWidget(w, 0, gridCol)
            gridCol += 1

        vbox = QVBoxLayout()
        vbox.addLayout(grid)
        vbox.addLayout(grid2)
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)

        self.main_frame.setLayout(vbox)
        self.setCentralWidget(self.main_frame)

    def on_minor_change(self):
        self.on_draw(self.is_data)

    def on_draw(self, *args):
        # Get x-domain from user input
        self.LB_input = unicode(self.lowerbound.text())
        self.UB_input = unicode(self.upperbound.text())

        # Message box error if the domain inputs aren't int or float types
        # If float, round to the nearest 0.1
        round_to = 10
        try:
            self.LB_float = int(self.LB_input) * round_to
            self.UB_float = int(self.UB_input) * round_to
        except:
            self.LB_UB_defaults()
            QMessageBox.question(
                self, 'Error',
                '<center>Minimum and maximum values must be<br />\
                integer or floating-point numbers.</center>', QMessageBox.Ok)

        # Make sure UB > LB
        if self.UB_float <= self.LB_float:
            self.LB_UB_defaults()
            QMessageBox.question(
                self, 'Error', '<center>Maximum must be greater\
                than minimum value.</center>', QMessageBox.Ok)

        # If plotting a function, then get x and y values
        if len(args) == 0:
            self.is_data = False

            # Set x values (/round_to is to use range() with floating-point numbers)
            self.input_x = range(self.LB_float, self.UB_float + 1)
            self.input_x = [i / float(round_to) for i in self.input_x]

            # Calculate f(x) values for specified function
            fx = unicode(self.textbox.text())
            # If the f(x) field is empty, then default to y = 0 plot
            if fx == '':
                self.y = [0 for i in self.input_x]
            # Otherwise, evaluate the specified function and get ready to plot
            else:
                # Replace exp with numbers
                fx = fx.replace('exp', str(exp(1)) + '**')
                # Allow users to enter ^ for powers (replace ^ with **)
                fx = fx.replace('^', '**')
                # Try and evaluate; if there is an error, then shift slightly to the right
                try:
                    self.y = [eval(fx) for x in self.input_x]
                except:
                    fx = fx.replace('x', '(x + 10**(-6))')
                    self.y = [eval(fx) for x in self.input_x]
            self.plot_symbol = '-'
        if self.is_data:
            self.plot_symbol = 'o'

        # If the hold box is checked, then new plots do not erase old ones
        new_state = self.quad_check()
        if self.axis_state == 0:
            self.axes.hold(self.hold_cb.isChecked())
        else:
            if self.hold_cb.isChecked():
                # If 'hold' is checked, see what quadrants will be shown
                # - if the quadrant state changes, remove subplots
                # - otherwise retain subplots
                if self.axis_state == 0 and new_state == 0:
                    self.axes.hold(self.hold_cb.isChecked())
                elif self.axis_state == 3 and new_state == 3:
                    self.axes_Q1.hold(self.hold_cb.isChecked())
                    self.axes_Q2.hold(self.hold_cb.isChecked())
                    self.axes_Q3.hold(self.hold_cb.isChecked())
                    self.axes_Q4.hold(self.hold_cb.isChecked())
                elif self.axis_state == 1 and new_state == 1:
                    self.axes_Q1.hold(self.hold_cb.isChecked())
                    self.axes_Q2.hold(self.hold_cb.isChecked())
                elif self.axis_state == 2 and new_state == 2:
                    self.axes_Q1.hold(self.hold_cb.isChecked())
                    self.axes_Q4.hold(self.hold_cb.isChecked())
                else:
                    self.remove_subplots()
            else:
                self.remove_subplots()

        # If show negative box is unchecked
        if not self.trunc_cb.isChecked():
            self.add_main()
            self.axes.plot(self.input_x, self.y, self.plot_symbol)
            if not self.logx_cb.isChecked() and not self.logy_cb.isChecked():
                self.axes.set_xscale('linear')
                self.axes.set_yscale('linear')
            elif self.logx_cb.isChecked() and not self.logy_cb.isChecked():
                self.axes.set_xscale('log')
                self.axes.set_yscale('linear')
            elif not self.logx_cb.isChecked() and self.logy_cb.isChecked():
                self.axes.set_xscale('linear')
                self.axes.set_yscale('log')
            else:
                self.axes.set_xscale('log')
                self.axes.set_yscale('log')
        else:
            # Linear plot
            #if not self.logx_cb.isChecked() and not self.logy_cb.isChecked():
            if new_state == 0:
                self.add_main()
                self.axes.plot(self.input_x, self.y, self.plot_symbol)

            # Log x, linear y plot
            #elif self.logx_cb.isChecked() and not self.logy_cb.isChecked():
            elif new_state == 1:
                if not self.trunc_cb.isChecked():
                    self.add_main()
                    self.axes.semilogx(self.input_x, self.y, self.plot_symbol)
                else:
                    self.trunc_logx()

            # Linear x, log y plot
            #elif not self.logx_cb.isChecked() and self.logy_cb.isChecked():
            elif new_state == 2:
                if not self.trunc_cb.isChecked():
                    self.add_main()
                    self.axes.semilogy(self.input_x, self.y, self.plot_symbol)
                else:
                    self.trunc_logy()

            # Log-log plot
            else:
                if not self.trunc_cb.isChecked():
                    self.add_main()
                    self.axes.loglog(self.input_x, self.y, self.plot_symbol)
                else:
                    self.trunc_loglog()

        # Add grid if grid checkbox is checked
        if self.axis_state == 0:
            self.axes.grid(self.grid_cb.isChecked())
        else:
            if hasattr(self, 'axes_Q1'):
                self.axes_Q1.grid(self.grid_cb.isChecked())
            if hasattr(self, 'axes_Q2'):
                self.axes_Q2.grid(self.grid_cb.isChecked())
            if hasattr(self, 'axes_Q3'):
                self.axes_Q3.grid(self.grid_cb.isChecked())
            if hasattr(self, 'axes_Q4'):
                self.axes_Q4.grid(self.grid_cb.isChecked())

        self.axes.set_xlabel('$x$')
        self.axes.set_ylabel('$f(x)$')
        self.canvas.draw()
        self.guardarImagen()

    def remove_subplots(self):
        # Remove all subplots and axis flip flags
        if hasattr(self, 'axes_Q1'):
            self.fig.delaxes(self.axes_Q1)
            del self.axes_Q1
        if hasattr(self, 'axes_Q2'):
            self.fig.delaxes(self.axes_Q2)
            del self.axes_Q2
            if hasattr(self, 'flip_Q2'):
                del self.flip_Q2
        if hasattr(self, 'axes_Q3'):
            self.fig.delaxes(self.axes_Q3)
            del self.axes_Q3
            del self.flip_Q3
        if hasattr(self, 'axes_Q4'):
            self.fig.delaxes(self.axes_Q4)
            del self.axes_Q4
            if hasattr(self, 'flip_Q4'):
                del self.flip_Q4

    def add_main(self):
        # Reinsert the main plot
        if self.axis_state > 0:
            self.remove_subplots()
            self.axes = self.fig.add_subplot(111)
            self.axis_state = 0

    def create_menu(self):
        exitAction = QAction('Quit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)

        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')

        save_plot_action = self.create_action("&Save plot",
                                              shortcut="Ctrl+S",
                                              slot=self.save_plot,
                                              tip="Save image to file")
        import_data_action = self.create_action("&Import data",
                                                shortcut="Ctrl+I",
                                                slot=self.import_data,
                                                tip="Import data from file")
        fileMenu.addAction(save_plot_action)
        fileMenu.addAction(import_data_action)
        fileMenu.addAction(exitAction)

        helpMenu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About",
                                          shortcut='F1',
                                          slot=self.on_about,
                                          tip='About CutePlot')
        helpMenu.addAction(about_action)

    def create_action(self,
                      text,
                      slot=None,
                      shortcut=None,
                      icon=None,
                      tip=None,
                      checkable=False,
                      signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def save_plot(self):
        file_choices = "PNG (*.png)"
        path = unicode(
            QFileDialog.getSaveFileName(self, 'Save file', '', file_choices))
        if path:
            self.canvas.print_figure(path, dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)

    def import_data(self):
        file_choices = "*.csv;;*.txt;;*.tab;;*.dat;;*.*"
        self.path = QFileDialog.getOpenFileName(self, 'Import data', '',
                                                file_choices)
        if self.path:
            datafile = open(self.path[0], 'r')
            if datafile:
                self.is_data = True
                delimiter = ','
                input_xy = [
                    map(float,
                        line.strip().split(delimiter)) for line in datafile
                ]
                self.input_x, self.y = [[row[col] for row in input_xy]
                                        for col in [0, 1]]
                datafile.close()
                self.statusBar().showMessage('Imported data', 2000)
                self.on_draw(self.is_data)

    def on_about(self):
        msg = """<center><b>CutePlot v. 0.1</b></center>
        <center>Free, open-source plotting program,<br />
        written in Python (PySide/Qt + matplotlib).</center>
        <center>(c) Jack Peterson, 2012</center>
        """
        QMessageBox.about(self, "About", msg.strip())

    def quad_check(self):
        # Q = quadrant
        Q1 = False
        Q2 = False
        Q3 = False
        Q4 = False

        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1 = True
            elif self.input_x[j] < 0 and self.y[j] > 0:
                Q2 = True
            elif self.input_x[j] < 0 and self.y[j] < 0:
                Q3 = True
            elif self.input_x[j] > 0 and self.y[j] < 0:
                Q4 = True

        if (Q3 or (Q2 and Q4) or ((Q2 or Q4) and self.axis_state == 3)
            ) and self.logx_cb.isChecked() and self.logy_cb.isChecked():
            new_state = 3
        elif (Q2 and self.logx_cb.isChecked()) or (self.hold_cb.isChecked()
                                                   and self.axis_state == 1):
            new_state = 1
        elif (Q4 and self.logy_cb.isChecked()) or (self.hold_cb.isChecked()
                                                   and self.axis_state == 2):
            new_state = 2
        else:
            new_state = 0

        return new_state

    def trunc_logx(self):
        # Q = quadrant
        Q1_x = []
        Q1_y = []
        Q2_x = []
        Q2_y = []

        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1_x.append(self.input_x[j])
                Q1_y.append(self.y[j])
            elif self.input_x[j] < 0 and self.y[j] > 0:
                Q2_x.append(-self.input_x[j])
                Q2_y.append(self.y[j])

        # If only Q1 is populated, then use an ordinary semilogx plot
        if Q2_x == [] and not self.hold_cb.isChecked():
            self.add_main()
            self.axes.semilogx(self.input_x, self.y, self.plot_symbol)

        # Otherwise, create a truncated plot
        else:
            # Remove main axes
            if self.axis_state == 0:
                self.fig.delaxes(self.axes)

            if self.axis_state == 2 or self.axis_state == 3:
                self.axis_state = 3
            else:
                self.axis_state = 1

            # Create 2 subplots
            self.axes_Q1 = self.fig.add_subplot(122)
            self.axes_Q2 = self.fig.add_subplot(121)
            self.axes_Q1.autoscale(enable=True)
            self.axes_Q2.autoscale(enable=True)
            self.axes_Q1.semilogx(Q1_x, Q1_y, self.plot_symbol)
            self.axes_Q2.semilogx(Q2_x, Q2_y, self.plot_symbol)

            # Reverse Q2 x-axis
            if not hasattr(self, 'flip_Q2'):
                self.flip_Q2 = True
                self.axes_Q2.set_xlim(self.axes_Q2.get_xlim()[::-1])

            # Set axis tickmarks at powers of 10
            # Q1 axes
            if Q1_x == [] and not self.hold_cb.isChecked():
                self.axes_Q1.set_xticklabels([])
            else:
                try:
                    x_UB_Q1 = int(ceil(log10(max(Q1_x))))
                    x_LB_Q1 = int(floor(log10(min(Q1_x))))
                except:
                    x_UB_Q1 = 2
                    x_LB_Q1 = -1
                Q1_xlabels = []
                for i in range(x_LB_Q1, x_UB_Q1 + 1):
                    Q1_xlabels.append('$10^{%s}$' % str(i))
                self.axes_Q1.set_xticklabels(Q1_xlabels)
            self.axes_Q1.xaxis.tick_bottom()
            self.axes_Q1.yaxis.tick_right()

            # Q2 axes
            if Q2_x == [] and not self.hold_cb.isChecked():
                self.axes_Q2.set_xticklabels([])
            else:
                try:
                    x_UB_Q2 = int(ceil(log10(max(Q2_x))))
                    x_LB_Q2 = int(floor(log10(min(Q2_x))))
                except:
                    x_UB_Q2 = 2
                    x_LB_Q2 = -1
                Q2_xlabels = []
                for i in range(x_LB_Q2, x_UB_Q2 + 1):
                    Q2_xlabels.append('$-10^{%s}$' % str(i))
                self.axes_Q2.set_xticklabels(Q2_xlabels)
            self.axes_Q2.xaxis.tick_bottom()
            self.axes_Q2.yaxis.tick_left()

    def trunc_logy(self):
        # Q = quadrant
        Q1_x = []
        Q1_y = []
        Q4_x = []
        Q4_y = []

        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1_x.append(self.input_x[j])
                Q1_y.append(self.y[j])
            elif self.input_x[j] > 0 and self.y[j] < 0:
                Q4_x.append(self.input_x[j])
                Q4_y.append(-self.y[j])

        # If only Q1 is populated, then use an ordinary semilogy plot
        if Q4_x == [] and not self.hold_cb.isChecked():
            self.add_main()
            self.axes.semilogy(self.input_x, self.y, self.plot_symbol)

        # Otherwise, create a truncated plot
        else:
            # Remove main axes
            if self.axis_state == 0:
                self.fig.delaxes(self.axes)

            if self.axis_state == 1 or self.axis_state == 3:
                self.axis_state = 3
            else:
                self.axis_state = 2

            # Create 2 subplots
            self.axes_Q1 = self.fig.add_subplot(211)
            self.axes_Q4 = self.fig.add_subplot(212)
            self.axes_Q1.autoscale(enable=True)
            self.axes_Q4.autoscale(enable=True)
            self.axes_Q1.semilogy(Q1_x, Q1_y, self.plot_symbol)
            self.axes_Q4.semilogy(Q4_x, Q4_y, self.plot_symbol)

            # Reverse Q4 y-axis
            if not hasattr(self, 'flip_Q4'):
                self.flip_Q4 = True
                self.axes_Q4.set_ylim(self.axes_Q4.get_ylim()[::-1])

            # Set axis tickmarks at powers of 10
            # Q1 axes
            if Q1_x == [] and not self.hold_cb.isChecked():
                self.axes_Q1.set_yticklabels([])
            else:
                try:
                    y_UB_Q1 = int(ceil(log10(max(Q1_y))))
                    y_LB_Q1 = int(floor(log10(min(Q1_y))))
                except:
                    y_UB_Q1 = 2
                    y_LB_Q1 = -1
                Q1_ylabels = []
                for i in range(y_LB_Q1, y_UB_Q1 + 1):
                    Q1_ylabels.append('$10^{%s}$' % str(i))
                self.axes_Q1.set_yticklabels(Q1_ylabels)
            self.axes_Q1.xaxis.tick_top()
            self.axes_Q1.yaxis.tick_right()

            # Q4 axes
            if Q4_x == [] and not self.hold_cb.isChecked():
                self.axes_Q4.set_yticklabels([])
            else:
                try:
                    y_UB_Q4 = int(ceil(log10(max(Q4_y))))
                    y_LB_Q4 = int(floor(log10(min(Q4_y))))
                except:
                    y_UB_Q4 = 2
                    y_LB_Q4 = -1
                Q4_ylabels = []
                for i in range(y_LB_Q4, y_UB_Q4 + 1):
                    Q4_ylabels.append('$-10^{%s}$' % str(i))
                self.axes_Q4.set_yticklabels(Q4_ylabels)
            self.axes_Q4.xaxis.tick_bottom()
            self.axes_Q4.yaxis.tick_right()

    def trunc_loglog(self):
        # Q = quadrant
        Q1_x = []
        Q1_y = []
        Q2_x = []
        Q2_y = []
        Q3_x = []
        Q3_y = []
        Q4_x = []
        Q4_y = []

        # Split the x and y values by sign
        for j in range(0, len(self.input_x)):
            if self.input_x[j] > 0 and self.y[j] > 0:
                Q1_x.append(self.input_x[j])
                Q1_y.append(self.y[j])
            elif self.input_x[j] < 0 and self.y[j] > 0:
                Q2_x.append(-self.input_x[j])
                Q2_y.append(self.y[j])
            elif self.input_x[j] < 0 and self.y[j] < 0:
                Q3_x.append(-self.input_x[j])
                Q3_y.append(-self.y[j])
            elif self.input_x[j] > 0 and self.y[j] < 0:
                Q4_x.append(self.input_x[j])
                Q4_y.append(-self.y[j])

        # If only Q1 is populated, then use an ordinary loglog plot
        if Q2_x == [] and Q3_x == [] and Q4_x == [] and not self.hold_cb.isChecked(
        ):
            self.add_main()
            self.axes.loglog(self.input_x, self.y, self.plot_symbol)

        # Otherwise, create a truncated plot
        else:
            # Remove main axes
            if self.axis_state == 0:
                self.fig.delaxes(self.axes)
            self.axis_state = 3

            # Create 4 subplots
            self.axes_Q1 = self.fig.add_subplot(222)
            self.axes_Q2 = self.fig.add_subplot(221)
            self.axes_Q3 = self.fig.add_subplot(223)
            self.axes_Q4 = self.fig.add_subplot(224)
            self.axes_Q1.autoscale(enable=True)
            self.axes_Q2.autoscale(enable=True)
            self.axes_Q3.autoscale(enable=True)
            self.axes_Q4.autoscale(enable=True)
            self.axes_Q1.loglog(Q1_x, Q1_y, self.plot_symbol)
            self.axes_Q2.loglog(Q2_x, Q2_y, self.plot_symbol)
            self.axes_Q3.loglog(Q3_x, Q3_y, self.plot_symbol)
            self.axes_Q4.loglog(Q4_x, Q4_y, self.plot_symbol)

            if not hasattr(self, 'flip_Q3'):
                self.flip_Q3 = True

                # Reverse Q2 x-axis
                self.axes_Q2.set_xlim(self.axes_Q2.get_xlim()[::-1])

                # Reverse Q3 x- and y-axes
                self.axes_Q3.set_xlim(self.axes_Q3.get_xlim()[::-1])
                self.axes_Q3.set_ylim(self.axes_Q3.get_ylim()[::-1])

                # Reverse Q4 y-axis
                self.axes_Q4.set_ylim(self.axes_Q4.get_ylim()[::-1])

            # Set axis tickmarks at powers of 10
            # Q1 axes
            if Q1_x == [] and not self.hold_cb.isChecked():
                self.axes_Q1.set_xticklabels([])
                self.axes_Q1.set_yticklabels([])
            else:
                try:
                    x_UB_Q1 = int(ceil(log10(max(Q1_x))))
                    y_UB_Q1 = int(ceil(log10(max(Q1_y))))
                    x_LB_Q1 = int(floor(log10(min(Q1_x))))
                    y_LB_Q1 = int(floor(log10(min(Q1_y))))
                except:
                    x_UB_Q1 = 2
                    y_UB_Q1 = 2
                    x_LB_Q1 = -1
                    y_LB_Q1 = -1
                Q1_xlabels = []
                Q1_ylabels = []
                for i in range(x_LB_Q1, x_UB_Q1 + 1):
                    Q1_xlabels.append('$10^{%s}$' % str(i))
                for i in range(y_LB_Q1, y_UB_Q1 + 1):
                    Q1_ylabels.append('$10^{%s}$' % str(i))
                self.axes_Q1.set_xticklabels(Q1_xlabels)
                self.axes_Q1.set_yticklabels(Q1_ylabels)
            self.axes_Q1.xaxis.tick_top()
            self.axes_Q1.yaxis.tick_right()

            # Q2 axes
            if Q2_x == [] and not self.hold_cb.isChecked():
                self.axes_Q2.set_xticklabels([])
                self.axes_Q2.set_yticklabels([])
            else:
                try:
                    x_UB_Q2 = int(ceil(log10(max(Q2_x))))
                    y_UB_Q2 = int(ceil(log10(max(Q2_y))))
                    x_LB_Q2 = int(floor(log10(min(Q2_x))))
                    y_LB_Q2 = int(floor(log10(min(Q2_y))))
                except:
                    x_UB_Q2 = 2
                    y_UB_Q2 = 2
                    x_LB_Q2 = -1
                    y_LB_Q2 = -1
                Q2_xlabels = []
                Q2_ylabels = []
                for i in range(x_LB_Q2, x_UB_Q2 + 1):
                    Q2_xlabels.append('$-10^{%s}$' % str(i))
                for i in range(y_LB_Q2, y_UB_Q2 + 1):
                    Q2_ylabels.append('$10^{%s}$' % str(i))
                self.axes_Q2.set_xticklabels(Q2_xlabels)
                self.axes_Q2.set_yticklabels(Q2_ylabels)
            self.axes_Q2.xaxis.tick_top()
            self.axes_Q2.yaxis.tick_left()

            # Q3 axes
            if Q3_x == [] and not self.hold_cb.isChecked():
                self.axes_Q3.set_xticklabels([])
                self.axes_Q3.set_yticklabels([])
            else:
                try:
                    x_UB_Q3 = int(ceil(log10(max(Q3_x))))
                    y_UB_Q3 = int(ceil(log10(max(Q3_y))))
                    x_LB_Q3 = int(floor(log10(min(Q3_x))))
                    y_LB_Q3 = int(floor(log10(min(Q3_y))))
                except:
                    x_UB_Q3 = 2
                    y_UB_Q3 = 2
                    x_LB_Q3 = -1
                    y_LB_Q3 = -1
                Q3_xlabels = []
                Q3_ylabels = []
                for i in range(x_LB_Q3, x_UB_Q3 + 1):
                    Q3_xlabels.append('$-10^{%s}$' % str(i))
                for i in range(y_LB_Q3, y_UB_Q3 + 1):
                    Q3_ylabels.append('$-10^{%s}$' % str(i))
                self.axes_Q3.set_xticklabels(Q3_xlabels)
                self.axes_Q3.set_yticklabels(Q3_ylabels)
            self.axes_Q3.xaxis.tick_bottom()
            self.axes_Q3.yaxis.tick_left()

            # Q4 axes
            if Q4_x == [] and not self.hold_cb.isChecked():
                self.axes_Q4.set_xticklabels([])
                self.axes_Q4.set_yticklabels([])
            else:
                try:
                    x_UB_Q4 = int(ceil(log10(max(Q4_x))))
                    y_UB_Q4 = int(ceil(log10(max(Q4_y))))
                    x_LB_Q4 = int(floor(log10(min(Q4_x))))
                    y_LB_Q4 = int(floor(log10(min(Q4_y))))
                except:
                    x_UB_Q4 = 2
                    y_UB_Q4 = 2
                    x_LB_Q4 = -1
                    y_LB_Q4 = -1
                Q4_xlabels = []
                Q4_ylabels = []
                for i in range(x_LB_Q4, x_UB_Q4 + 1):
                    Q4_xlabels.append('$10^{%s}$' % str(i))
                for i in range(y_LB_Q4, y_UB_Q4 + 1):
                    Q4_ylabels.append('$-10^{%s}$' % str(i))
                self.axes_Q4.set_xticklabels(Q4_xlabels)
                self.axes_Q4.set_yticklabels(Q4_ylabels)
            self.axes_Q4.xaxis.tick_bottom()
            self.axes_Q4.yaxis.tick_right()

    def guardarImagen(self):
        path = os.path.abspath("untitled.png")
        self.canvas.resize(460, 261)
        self.canvas.print_figure(path, dpi=self.dpi)
        self.statusBar().showMessage('Saved to %s' % path, 2000)
        self.canvas.resize(560, 361)
예제 #43
0
파일: plot_grid.py 프로젝트: tjlang/artview
class GridDisplay(Component):
    '''
    Class to create a display plot, using a Grid structure.
    '''

    Vgrid = None #: see :ref:`shared_variable`
    Vfield = None #: see :ref:`shared_variable`
    VlevelZ = None \
    #: see :ref:`shared_variable`, only used if plot_type="gridZ"
    VlevelY = None \
    #: see :ref:`shared_variable`, only used if plot_type="gridY"
    VlevelX = None \
    #: see :ref:`shared_variable`, only used if plot_type="gridX"
    Vcmap = None #: see :ref:`shared_variable`

    @classmethod
    def guiStart(self, parent=None):
        '''Graphical interface for starting this class'''
        args = _DisplayStart().startDisplay()
        return self(**args), True

    def __init__(self, Vgrid, Vfield, VlevelZ=None, VlevelY=None,
                 VlevelX=None, Vlims=None, Vcmap=None, plot_type="gridZ",
                 name="Display", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        Vgrid : :py:class:`~artview.core.core.Variable` instance
            grid signal variable.
        Vfield : :py:class:`~artview.core.core.Variable` instance
            Field signal variable.
        [Optional]
        VlevelZ : :py:class:`~artview.core.core.Variable` instance
            Signal variable for vertical level, only used if
            plot_type="gridZ". If None start with value zero.
        VlevelY : :py:class:`~artview.core.core.Variable` instance
            Signal variable for latitudinal level, only used if
            plot_type="gridY". If None start with value zero.
        VlevelX : :py:class:`~artview.core.core.Variable` instance
            Signal variable for longitudinal level, only used if
            plot_type="gridX". If None start with value zero.
        Vlims : :py:class:`~artview.core.core.Variable` instance
            Limits signal variable.
            A value of None will instantiate a limits variable.
        Vcmap : :py:class:`~artview.core.core.Variable` instance
            Colormap signal variable.
            A value of None will instantiate a colormap variable.
        plot_type : "gridZ", "gridY" or "gridX"
            Define plot type, "gridZ" will plot a Z level, that is a XY
            plane. Analog for "gridY" and "gridZ"
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        Notes
        -----
        This class records the selected button and passes the
        change value back to variable.
        '''
        super(GridDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)
        # Set up signal, so that DISPLAY can react to
        # external (or internal) changes in grid, field,
        # lims and level (expected to be Core.Variable instances)
        # The capital V so people remember using ".value"
        self.Vgrid = Vgrid
        self.Vfield = Vfield
        if VlevelZ is None:
            self.VlevelZ = Variable(0)
        else:
            self.VlevelZ = VlevelZ
        if VlevelY is None:
            self.VlevelY = Variable(0)
        else:
            self.VlevelY = VlevelY
        if VlevelX is None:
            self.VlevelX = Variable(0)
        else:
            self.VlevelX = VlevelX
        if Vlims is None:
            self.Vlims = Variable(None)
        else:
            self.Vlims = Vlims

        if Vcmap is None:
            self.Vcmap = Variable(None)
        else:
            self.Vcmap = Vcmap

        self.sharedVariables = {"Vgrid": self.Newgrid,
                                "Vfield": self.NewField,
                                "Vlims": self.NewLims,
                                "Vcmap": self.NewCmap,}

        self.change_plot_type(plot_type)

        # Connect the components
        self.connectAllVariables()

        # Set plot title and colorbar units to defaults
        # TODO convert title to grid
        #self.title = None
        self.units = None

        # set default latlon lines
        self.lat_lines = np.linspace(-90, 90, num=181)
        self.lon_lines = np.linspace(-180, 180, num=361)

        # Find the PyArt colormap names
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create tool dictionary
        self.tools = {}

        # Set up Default limits and cmap
        if Vlims is None:
            self._set_default_limits(strong=False)
        if Vcmap is None:
            self._set_default_cmap(strong=False)

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Initialize grid variable
        self.Newgrid(None, None, True)

        self.show()

    def keyPressEvent(self, event):
        '''Allow level adjustment via the Up-Down arrow keys.'''
        if event.key() == QtCore.Qt.Key_Up:
            self.LevelSelectCmd(self.Vlevel.value + 1)
        elif event.key() == QtCore.Qt.Key_Down:
            self.LevelSelectCmd(self.Vlevel.value - 1)
        else:
            super(GridDisplay, self).keyPressEvent(event)

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(8)

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add buttons along display for user control
        self.addButtons()
        self.setUILayout()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    ##################################
    # User display interface methods #
    ##################################
    def addButtons(self):
        '''Add a series of buttons for user control over display.'''
        # Create the Display controls
        self._add_displayBoxUI()
        # Create the Level controls
        self._add_levelBoxUI()
        # Create the Field controls
        self._add_fieldBoxUI()
        # Create the Tools controls
        self._add_toolsBoxUI()

    def setUILayout(self):
        '''Setup the button/display UI layout.'''
        self.layout.addWidget(self.levelBox, 0, 0)
        self.layout.addWidget(self.fieldBox, 0, 1)
        self.layout.addWidget(self.dispButton, 0, 2)
        self.layout.addWidget(self.toolsButton, 0, 3)

    #############################
    # Functionality methods #
    #############################

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(self.Vlims.value, self.Vcmap.value, self.name)
        if change == 1:
            self.Vcmap.change(cmap, False)
            print(limits)
            self.Vlims.change(limits)
            print(self.Vlims.value)

    def _fillLevelBox(self):
        '''Fill in the Level Window Box with current levels.'''
        self.levelBox.clear()
        self.levelBox.addItem("Level Window")
        # Loop through and create each level button
        if self.plot_type == "gridZ":
            levels = self.Vgrid.value.axes['z_disp']['data']
        elif self.plot_type == "gridY":
            levels = self.Vgrid.value.axes['y_disp']['data']
        elif self.plot_type == "gridX":
            levels = self.Vgrid.value.axes['x_disp']['data']

        for nlevel in range(len(levels)):
            btntxt = "%2.1f m (level %d)"%(levels[nlevel], nlevel+1)
            self.levelBox.addItem(btntxt)

    def _fillFieldBox(self):
        '''Fill in the Field Window Box with current variable names.'''
        self.fieldBox.clear()
        self.fieldBox.addItem("Field Window")
        # Loop through and create each field button
        for field in self.fieldnames:
            self.fieldBox.addItem(field)

    def _levelAction(self, text):
        '''Define action for Level Button selection.'''
        if text == "Level Window":
            self._open_levelbuttonwindow()
        else:
            nlevel = int(text.split("(level ")[1][:-1])-1
            self.LevelSelectCmd(nlevel)

    def _fieldAction(self, text):
        '''Define action for Field Button selection.'''
        if text == "Field Window":
            self._open_fieldbuttonwindow()
        else:
            self.FieldSelectCmd(str(text))

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog(self.title, "Plot Title", "Title:")
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog(self.units, "Plot Units", "Units:")
        if entry is True:
            self.units = val
            self._update_plot()

    def _open_levelbuttonwindow(self):
        '''Open a LevelButtonWindow instance.'''
        from .level import LevelButtonWindow
        self.levelbuttonwindow = LevelButtonWindow(
            self.Vlevel, self.plot_type, Vcontainer=self.Vgrid,
            name=self.name+" Level Selection", parent=self.parent)

    def _open_fieldbuttonwindow(self):
        '''Open a FieldButtonWindow instance.'''
        from .field import FieldButtonWindow
        self.fieldbuttonwindow = FieldButtonWindow(
            self.Vgrid, self.Vfield,
            name=self.name+" Field Selection", parent=self.parent)

    def _add_cmaps_to_button(self):
        '''Add a menu to change colormap used for plot.'''
        for cm_name in self.cm_names:
            cmapAction = self.dispCmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap" % cm_name)
            cmapAction.triggered[()].connect(
                lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
            self.dispCmap.setMenu(self.dispCmapmenu)

    def _add_displayBoxUI(self):
        '''Create the Display Options Button menu.'''
        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = dispmenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
        # TODO convert me to grid
        #dispTitle = dispmenu.addAction("Change Title")
        #dispTitle.setToolTip("Change plot title")
        dispUnit = dispmenu.addAction("Change Units")
        dispUnit.setToolTip("Change units string")
        self.dispCmap = dispmenu.addAction("Change Colormap")
        self.dispCmapmenu = QtGui.QMenu("Change Cmap")
        self.dispCmapmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        #dispQuickSave = dispmenu.addAction("Quick Save Image")
        #dispQuickSave.setShortcut("Ctrl+D")
        #dispQuickSave.setStatusTip(
        #    "Save Image to local directory with default name")
        #dispSaveFile = dispmenu.addAction("Save Image")
        #dispSaveFile.setShortcut("Ctrl+S")
        #dispSaveFile.setStatusTip("Save Image using dialog")

        dispLimits.triggered[()].connect(self._open_LimsDialog)
        #dispTitle.triggered[()].connect(self._title_input)
        dispUnit.triggered[()].connect(self._units_input)
        #dispQuickSave.triggered[()].connect(self._quick_savefile)
        #dispSaveFile.triggered[()].connect(self._savefile)

        self._add_cmaps_to_button()
        self.dispButton.setMenu(dispmenu)

    def _add_levelBoxUI(self):
        '''Create the Level Selection ComboBox.'''
        self.levelBox = QtGui.QComboBox()
        self.levelBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.levelBox.setToolTip("Choose level")
        self.levelBox.activated[str].connect(self._levelAction)

    def _add_fieldBoxUI(self):
        '''Create the Field Selection ComboBox.'''
        self.fieldBox = QtGui.QComboBox()
        self.fieldBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.fieldBox.setToolTip("Choose variable/field")
        self.fieldBox.activated[str].connect(self._fieldAction)

    def _add_toolsBoxUI(self):
        '''Create the Tools Button menu.'''
        self.toolsButton = QtGui.QPushButton("Toolbox")
        self.toolsButton.setFocusPolicy(QtCore.Qt.NoFocus)
        self.toolsButton.setToolTip("Choose a tool to apply")
        toolmenu = QtGui.QMenu(self)
        toolZoomPan = toolmenu.addAction("Zoom/Pan")
        toolValueClick = toolmenu.addAction("Click for Value")
        toolSelectRegion = toolmenu.addAction("Select a Region of Interest")
        toolCustom = toolmenu.addAction("Use Custom Tool")
        toolDefault = toolmenu.addAction("Reset File Defaults")
        toolZoomPan.triggered[()].connect(self.toolZoomPanCmd)
        toolValueClick.triggered[()].connect(self.toolValueClickCmd)
        toolSelectRegion.triggered[()].connect(self.toolSelectRegionCmd)
        toolCustom.triggered[()].connect(self.toolCustomCmd)
        toolDefault.triggered[()].connect(self.toolDefaultCmd)
        self.toolsButton.setMenu(toolmenu)

    ########################
    # Selectionion methods #
    ########################

    def Newgrid(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vgrid <artview.core.core.Variable>`.

        This will:

        * Update fields and levels lists and MenuBoxes
        * Check grid scan type and reset limits if needed
        * Reset units and title
        * If strong update: update plot
        '''
        # test for None
        if self.Vgrid.value is None:
            self.fieldBox.clear()
            self.levelBox.clear()
            return

        # Get field names
        self.fieldnames = self.Vgrid.value.fields.keys()

        # Check the file type and initialize limts
        self._check_file_type()

        # Update field and level MenuBox
        self._fillLevelBox()
        self._fillFieldBox()

        self.units = None
        self.title = None
        if strong:
            self._update_plot()

    def NewField(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vfield <artview.core.core.Variable>`.

        This will:

        * Reset colormap
        * Reset units
        * Update fields MenuBox
        * If strong update: update plot
        '''
        self._set_default_cmap(strong=False)
        self.units = None
        idx = self.fieldBox.findText(value)
        self.fieldBox.setCurrentIndex(idx)
        if strong and self.Vgrid.value is not None:
            self._update_plot()

    def NewLims(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlims <artview.core.core.Variable>`.

        This will:

        * If strong update: update axes
        '''
        if strong:
            self._update_axes()

    def NewCmap(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vcmap <artview.core.core.Variable>`.

        This will:

        * If strong update: update plot
        '''
        if strong and self.Vgrid.value is not None:
            self._update_plot()


    def NewLevel(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlevel* <artview.core.core.Variable>`.

        This will:

        * Update level MenuBox
        * If strong update: update plot
        '''
        # +1 since the first one is "Level Window"
        self.levelBox.setCurrentIndex(value+1)
        if strong and self.Vgrid.value is not None:
            self._update_plot()

    def LevelSelectCmd(self, nlevel):
        '''
        Captures Level selection and update Level
        :py:class:`~artview.core.core.Variable`.
        '''
        if nlevel < 0:
            nlevel = len(self.levels)-1
        elif nlevel >= len(self.levels):
            nlevel = 0
        self.Vlevel.change(nlevel)

    def FieldSelectCmd(self, name):
        '''
        Captures field selection and update field
        :py:class:`~artview.core.core.Variable`.
        '''
        self.Vfield.change(name)

    def cmapSelectCmd(self, cm_name):
        '''Captures colormap selection and redraws.'''
        CMAP = cm_name
        self.Vcmap.value['cmap'] = cm_name
        self.Vcmap.change(self.Vcmap.value)

    def toolZoomPanCmd(self):
        '''Creates and connects to a Zoom/Pan instance.'''
        from .tools import ZoomPan
        scale = 1.1
        self.tools['zoompan'] = ZoomPan(
            self.Vlims, self.ax,
            base_scale=scale, parent=self.parent)
        self.tools['zoompan'].connect()

    def toolValueClickCmd(self):
        '''Creates and connects to Point-and-click value retrieval'''
        from .pick_value import ValueClick
        self.tools['valueclick'] = ValueClick(
            self, name=self.name + "ValueClick", parent=self)

    def toolSelectRegionCmd(self):
        '''Creates and connects to Region of Interest instance.'''
        from .select_region import SelectRegion
        self.tools['select_region'] = SelectRegion(self, name=self.name + " SelectRegion", parent=self)

    def toolCustomCmd(self):
        '''Allow user to activate self-defined tool.'''
        from . import tools
        tools.custom_tool(self.tools)

    def toolDefaultCmd(self):
        '''Restore the Display defaults.'''
        from . import tools
        self.tools, limits, cmap = tools.restore_default_display(
            self.tools, self.Vfield.value, self.scan_type)
        self.Vcmap.change(cmap)
        self.Vlims.change(limits)

    def getPathInteriorValues(self, path):
        '''
        Return the bins values path.

        Parameters
        ----------
        path : Matplotlib Path instance

        Returns
        -------
        x, y, azi, range, value, ray_idx, range_inx: ndarray
            Truplet of 1arrays containing x,y coordinate, azimuth,
            range, current field value, ray index and range index
            for all bin of the current grid and tilt inside path.

        Notes
        -----
            If Vgrid.value is None, returns None
        '''
        # TODO convert to grid
        from .tools import interior_grid
        grid = self.Vgrid.value
        if grid is None:
            return (np.array([]),)*7

        xy, idx = interior_grid(path, grid, self.Vlevel.value, self.plot_type)
        aux = (xy[:, 0], xy[:, 1], grid.azimuth['data'][idx[:, 0]],
               grid.range['data'][idx[:, 1]] / 1000.,
               grid.fields[self.Vfield.value]['data'][idx[:, 0], idx[:, 1]],
               idx[:, 0], idx[:, 1])
        return aux

    def getNearestPoints(self, xdata, ydata):
        '''
        Return the bins values nearest to point.

        Parameters
        ----------
        xdata, ydata : float

        Returns
        -------
        x, y, z, value, x_idx, y_idx, z_idx: ndarray
            Truplet of 1arrays containing x,y,z coordinate, current field
            value, x, y and z index.

        Notes
        -----
            If Vgrid.value is None, returns None
        '''
        from .tools import nearest_point_grid
        grid = self.Vgrid.value
        if grid is None:
            return (np.array([]),)*7

        if self.plot_type == "gridZ":
            idx = nearest_point_grid(grid, self.levels[self.VlevelZ.value],
                                     ydata, xdata)
        elif self.plot_type == "gridY":
            idx = nearest_point_grid(grid, ydata,
                                     self.levels[self.VlevelY.value], x_data)
        elif self.plot_type == "gridX":
            idx = nearest_point_grid(grid, ydata, x_data,
                                     self.levels[self.VlevelX.value])
        aux = (grid.axes['x_disp']['data'][idx[:,2]],
               grid.axes['y_disp']['data'][idx[:,1]],
               grid.axes['z_disp']['data'][idx[:,0]],
               grid.fields[self.Vfield.value]['data'][idx[:, 0], idx[:, 1],
                                                      idx[:, 2]],
               idx[:, 2], idx[:, 1], idx[:, 0])
        return aux

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 8
        self.YSIZE = 8
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])
        self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
        #self._update_axes()

    def _update_fig_ax(self):
        '''Set the figure and axis to plot.'''
        if self.plot_type in ("gridX", "gridY"):
            self.YSIZE = 5
        else:
            self.YSIZE = 8
        xwidth = 0.7
        yheight = 0.7 * float(self.YSIZE) / float(self.XSIZE)
        self.ax.set_position([0.2, 0.55-0.5*yheight, xwidth, yheight])
        self.cax.set_position([0.2, 0.10, xwidth, 0.02])
        self._update_axes()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 7, 6)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''
        self._check_default_field()

        # Create the plot with PyArt GridMapDisplay
        self.ax.cla()  # Clear the plot axes
        self.cax.cla()  # Clear the colorbar axes

        if self.Vfield.value not in self.Vgrid.value.fields.keys():
            self.canvas.draw()
            return

        # Reset to default title if user entered nothing w/ Title button
        # TODO convert title to grid
        #if self.title == '':
        #    title = None
        #else:
        #    title = self.title

        limits = self.Vlims.value
        cmap = self.Vcmap.value

        self.display = pyart.graph.GridMapDisplay(self.Vgrid.value)
        # Create Plot
        if self.plot_type == "gridZ":
            self.display.plot_basemap(self.lat_lines, self.lon_lines,
                                      ax=self.ax)
            self.plot = self.display.plot_grid(
                    self.Vfield.value, self.VlevelZ.value, vmin=cmap['vmin'],
                    vmax=cmap['vmax'],cmap=cmap['cmap'])
        elif self.plot_type == "gridY":
             self.plot = self.display.plot_latitude_slice(
                    self.Vfield.value, vmin=cmap['vmin'],
                    vmax=cmap['vmax'],cmap=cmap['cmap'])
        elif self.plot_type == "gridX":
             self.plot = self.display.plot_longitude_slice(
                    self.Vfield.value, vmin=cmap['vmin'],
                    vmax=cmap['vmax'],cmap=cmap['cmap'])

        limits = self.Vlims.value
        x = self.ax.get_xlim()
        y = self.ax.get_ylim()
        limits['xmin'] = x[0]
        limits['xmax'] = x[1]
        limits['ymin'] = y[0]
        limits['ymax'] = y[1]

        self._update_axes()
        norm = mlabNormalize(vmin=cmap['vmin'],
                             vmax=cmap['vmax'])
        self.cbar = mlabColorbarBase(self.cax, cmap=cmap['cmap'],
                                     norm=norm, orientation='horizontal')
        # colorbar - use specified units or default depending on
        # what has or has not been entered
        if self.units is None or self.units == '':
            try:
                self.units = self.Vgrid.value.fields[self.field]['units']
            except:
                self.units = ''
        self.cbar.set_label(self.units)

        if self.plot_type == "gridZ":
            print("Plotting %s field, Z level %d in %s" % (
                self.Vfield.value, self.VlevelZ.value+1, self.name))
        elif self.plot_type == "gridY":
            print("Plotting %s field, Y level %d in %s" % (
                self.Vfield.value, self.VlevelY.value+1, self.name))
        elif self.plot_type == "gridX":
            print("Plotting %s field, X level %d in %s" % (
                self.Vfield.value, self.VlevelX.value+1, self.name))


        self.canvas.draw()

    def _update_axes(self):
        '''Change the Plot Axes.'''
        limits = self.Vlims.value
        self.ax.set_xlim(limits['xmin'], limits['xmax'])
        self.ax.set_ylim(limits['ymin'], limits['ymax'])
        self.ax.figure.canvas.draw()

    #########################
    # Check methods #
    #########################

    def _check_default_field(self):
        '''
        Hack to perform a check on reflectivity to make it work with
        #a larger number of files as there are many nomenclature is the
        weather radar world.

        This should only occur upon start up with a new file.
        '''
        if self.Vfield.value == pyart.config.get_field_name('reflectivity'):
            if self.Vfield.value in self.fieldnames:
                pass
            elif 'CZ' in self.fieldnames:
                self.Vfield.change('CZ', False)
            elif 'DZ' in self.fieldnames:
                self.Vfield.change('DZ', False)
            elif 'dbz' in self.fieldnames:
                self.Vfield.change('dbz', False)
            elif 'DBZ' in self.fieldnames:
                self.Vfield.change('DBZ', False)
            elif 'dBZ' in self.fieldnames:
                self.Vfield.change('dBZ', False)
            elif 'Z' in self.fieldnames:
                self.Vfield.change('Z', False)
            elif 'DBZ_S' in self.fieldnames:
                self.Vfield.change('DBZ_S', False)
            elif 'reflectivity_horizontal'in self.fieldnames:
                self.Vfield.change('reflectivity_horizontal', False)
            elif 'DBZH' in self.fieldnames:
                self.Vfield.change('DBZH', False)
            else:
                msg = "Could not find the field name.\n\
                      You can add an additional name by modifying the\n\
                      'check_default_field' function in plot.py\n\
                      Please send a note to ARTView folks to add this name\n\
                      Thanks!"
                common.ShowWarning(msg)

    def _set_default_limits(self, strong=True):
        '''Set limits to pre-defined default.'''
        # TODO convert me to grid
        from .limits import _default_limits
        limits, cmap = _default_limits(
            self.Vfield.value, "PPI")
        self.Vlims.change(limits, strong)

    def _set_default_cmap(self, strong=True):
        '''Set colormap to pre-defined default.'''
        # TODO convert me to grid
        from .limits import _default_limits
        limits, cmap = _default_limits(
            self.Vfield.value, "PPI")
        self.Vcmap.change(cmap, strong)

    def _check_file_type(self):
        '''Check file to see if the file type.'''
        #self._update_fig_ax()
        return

    def change_plot_type(self, plot_type):
        '''Change plot type.'''
        # remove shared variables
        for key in ("VlevelZ","VlevelY","VlevelX"):
            if key in self.sharedVariables.keys():
                del self.sharedVariables[key]
        if plot_type == "gridZ":
            self.sharedVariables["VlevelZ"] = self.NewLevel
        elif plot_type == "gridY":
            self.sharedVariables["VlevelY"] = self.NewLevel
        elif plot_type == "gridX":
            self.sharedVariables["VlevelX"] = self.NewLevel
        else:
            import warnings
            warnings.warn('Invalid Plot type %s, reseting to gridZ'%plot_type)
            self.sharedVariables["VlevelZ"] = self.NewLevel
            plot_type = "gridZ"
        self.plot_type = plot_type

    ########################
    # Image save methods #
    ########################
    # TODO convert me to grid - Update when PyArt updates this interface
    def _quick_savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display via PyArt interface.'''
        imagename = self.display.generate_filename(
            self.Vfield.value, self.Vlevel.value, ext=IMAGE_EXT)
        self.canvas.print_figure(os.path.join(os.getcwd(), imagename), dpi=DPI)
        self.statusbar.showMessage('Saved to %s' % os.path.join(os.getcwd(), imagename))

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        PBNAME = self.display.generate_filename(
            self.Vfield.value, self.Vlevel.value, ext=IMAGE_EXT)
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', PBNAME, file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)

    ########################
    #      get methods     #
    ########################

    def getPlotAxis(self):
        ''' get :py:class:`matplotlib.axes.Axes` instance of main plot '''
        return self.ax

    def getStatusBar(self):
        ''' get :py:class:`PyQt4.QtGui.QStatusBar` instance'''
        return self.statusbar

    def getField(self):
        ''' get current field '''
        return self.Vfield.value

    def getUnits(self):
        ''' get current units '''
        return self.units

    ########################
    #      Properties      #
    ########################

    @property
    def Vlevel(self):
        '''Alias to VlevelZ, VlevelY or VlevelX depending on plot_type.'''
        if self.plot_type == "gridZ":
            return self.VlevelZ
        elif self.plot_type == "gridY":
            return self.VlevelY
        elif self.plot_type == "gridX":
            return self.VlevelX
        else:
            return None

    @property
    def levels(self):
        '''Values from the axes of grid, depending on plot_type.'''
        if self.plot_type == "gridZ":
            return self.Vgrid.value.axes['z_disp']['data'][:]
        elif self.plot_type == "gridY":
            return self.Vgrid.value.axes['y_disp']['data'][:]
        elif self.plot_type == "gridX":
            return self.Vgrid.value.axes['x_disp']['data'][:]
        else:
            return None
예제 #44
0
class MainWindow(QMainWindow, Ui_MainWindow):
    '''Main application window'''
    
    selectedEdgeChanged = pyqtSignal(object)
    selectedEdgeChangedList = pyqtSignal(object) #when edge selected in QListWidget
    unitCellChanged = pyqtSignal()
    latticeVisibleChanged = pyqtSignal(object) # used to bind with mpl.event
    arrowsVisibleChanged = pyqtSignal(object) # used to bind with mpl.event
    
    def __init__(self, fileName=None, TEXT_MODE=True):
        
        super(MainWindow, self).__init__()
        self.setupUi(self)
        
        self.prefFileName = os.path.dirname(__file__)+'/../resources/preferences.xml'
        self.SETTINGS = ET.parse(self.prefFileName).getroot()
        self.CURRENT_THEME = DealXML.get_child_by_name(self.SETTINGS,"THEME","Current theme") 
        self.TEXT_MODE = TEXT_MODE
        
        self.size = (2,2,2)
        self.spinBox_sizeL.setValue(self.size[0])
        self.spinBox_sizeW.setValue(self.size[1])
        self.spinBox_sizeH.setValue(self.size[2])
        self.spinBox_type.clear()
        self.radioButton_output.setChecked(TEXT_MODE)

        self.setup_mpl_canvas()
        
        # initialize canvas
        path = self.prefFileName if fileName is None else fileName
        self.importXML_fromFile(path)
        self.fileNameXML = fileName
        self.label_fileNameXML.setText("XML library file:  " 
                                       + self.getFileLabelText())
        
        self.msb_noActiveEdge = QMessageBox()
        self.msb_noActiveEdge.setIcon(QMessageBox.Critical)
        self.msb_noActiveEdge.setWindowTitle("Message")    
        self.msb_noActiveEdge.setStandardButtons(QMessageBox.Ok)
        self.msb_noActiveEdge.setText("No edge is selected")
        
        # setup signals and slots
        self.btnEditXML.clicked.connect(self.editXML_callback)
        self.spinBox_sizeL.valueChanged.connect(self.changeSize_callback)
        self.spinBox_sizeW.valueChanged.connect(self.changeSize_callback)
        self.spinBox_sizeH.valueChanged.connect(self.changeSize_callback)
        self.btnDel.clicked.connect(self.delteEdge_callback)
        self.btnClear.clicked.connect(self.gee.clearEdges_callback)
        self.btnChangeType.clicked.connect(self.changeType_callback)
        self.btnLength.clicked.connect(self.addDistEdges_callback)
        self.listEdges.currentItemChanged.connect(self.selectEdgeList_callback)
        self.radioButton_output.toggled.connect(self.change_textMode)
        
        self.selectedEdgeChanged.connect(self.selectEdgeSignal_slot)
        self.unitCellChanged.connect(self.update_listEdges)
 
        self.setup_menu()
        
        if self.TEXT_MODE:
            print(self.gee.__doc__)

    def setup_menu(self):
        '''setup slot for menu actions'''
        
        # configure menuFile
        self.action_ImportXML.triggered.connect(self.importXMLdlg_callback)
        self.action_ImportCryst.triggered.connect(self.importCryst_callback)
        self.action_SaveXML.triggered.connect(self.saveXML_callback)  
        self.action_SaveXML_as.triggered.connect(self.saveXML_as_callback)
        self.action_ExportIMG.triggered.connect(self.exportIMG_callback)
        self.action_ExportAnim.triggered.connect(self.exportAnim_callback)
        self.action_Quit.triggered.connect(self.quit_callback)
        # configure menuEdit
        self.action_EditXML.triggered.connect(self.editXML_callback)
        self.action_AddSimEdges.triggered.connect(self.addSimEdges_callback)
        self.action_AddDistEdges.triggered.connect(self.addDistEdges_callback)
        self.action_ChangeType.triggered.connect(self.menuChangeType_callback)
        self.action_DelEdge.triggered.connect(self.delteEdge_callback)
        self.action_ClearEdges.triggered.connect(self.gee.clearEdges_callback)       
        self.action_Pref.triggered.connect(self.preferences_callback)
        # configure menuHelo
        self.action_About.triggered.connect(self.about_callback)
        self.action_Doc.triggered.connect(self.doc_callback)
        
    def setup_mpl_canvas(self):
        '''
        setup matplotlib manipulation pane widget 
        for displaying and editing lattice graph
        
        '''
        self.dpi = 100
        self.fig = Figure((5.0, 5.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.ax = self.fig.gca(projection='3d') 
        self.fig.subplots_adjust(left=0, bottom=0, right=1, top=1)
 
        self.canvas.setParent(self.mplWidget)
        self.mplLayout.addWidget(self.canvas)
        self.canvas.setFocusPolicy(Qt.ClickFocus)
        self.canvas.setFocus()
        
        # add aniation button
        self.btnPlay = QPushButton("Animate")
        self.btnPlay.setStatusTip("Open animation manager.")
        self.btnPlay.clicked.connect(self.exportAnim_callback)
        self.btnPlay.setFocusPolicy(Qt.NoFocus) 
        mplHbox = QHBoxLayout()
        mplHbox.addWidget(self.btnPlay)
        mplHbox.addStretch()
        mplVbox = QVBoxLayout()
        mplVbox.addLayout(mplHbox)
        mplVbox.addStretch()
        self.canvas.setLayout(mplVbox)
        
    def importXML_fromFile(self, path):
        '''import lattice graph form xml file'''
        
        self.fileNameXML = path
        self.parser = ParseXML(fileName = self.fileNameXML)
        LG_name_list = self.parser.get_LATTICEGRAPH_names()
        if len(LG_name_list) > 1:
            self.dlgSelectLG = DialogSelectLG(self, LG_name_list)
            self.dlgSelectLG.show()
        else:
            self.importXml(LG_name_list[0]) 
        
    def importXml(self, LG_name):
        '''import lattice graph with given name from predefined parser - ParseXML object'''
        
        self.LATTICEGRAPH_name = LG_name
        self.label_fileNameXML.setText("XML library file:  "+self.getFileLabelText())
        self.label_LG_name.setText("Lattice graph name:  "+self.LATTICEGRAPH_name)
        if self.parser is None:
            raise ValueError("Parser is not defined")
        self.lattice, self.UC = self.parser.parse_LATTICEGRAPH(self.LATTICEGRAPH_name)
        self.cluster = CrystalCluster(self.UC, self.lattice, self.size)
        self.ax.clear()
        self.gee = GraphEdgesEditor(self.ax, self.cluster, parent=self,                               
                                    display_report=True)
        self.canvas.draw()
 
        self.update_listEdges()
        self.unitCellChanged.emit()

    def update_listEdges(self):
        '''is used to update QListWidget when unit cell is changed''' 
        
        self.initialization = True # block QListWidget valuechanged callback
        
        self.listEdges.clear()
        defaultListItem = QListWidgetItem('')
        self.listEdges_idToItem = {None: defaultListItem}
        self.listEdges_ItemToId = {defaultListItem.text(): None}
         
        for key, edge in self.gee.UC.edges.items():
            newItem = QListWidgetItem(str(edge))
            self.listEdges.addItem(newItem)
            self.listEdges_idToItem[key] = newItem
            self.listEdges_ItemToId[newItem.text()] = key
        
        self.listEdges.addItem(defaultListItem)
        self.listEdges.setCurrentItem(defaultListItem)        
        self.initialization = False # relieze QListWidget valuechanged callback
        
    def changeSize_callback(self):
        '''called when cluter size in spinBox is chanaged'''
        self.size = (self.spinBox_sizeL.value(), 
                     self.spinBox_sizeW.value(),
                     self.spinBox_sizeH.value())
        self.gee.reset_size(self.size)        
        
    def changeType_callback(self):
        '''called when value of self.spinBox_type is changed'''
        if self.gee.e_active_ind is None:
            self.msb_noActiveEdge.exec_()            
        else:
            self.gee.change_active_edge_type(self.spinBox_type.value())

    def selectEdgeList_callback(self, selectedItem):
        '''called when edge is selected in QListWidget'''
        
        if not self.initialization:
            activeEdge_id = self.listEdges_ItemToId[selectedItem.text()]
            self.gee.select_edge(activeEdge_id)
            self.selectedEdgeChangedList.emit(activeEdge_id)
            if activeEdge_id is None:
                msg = " active edge unselected"
                self.spinBox_type.clear()
            else:
                msg = " selected edge: {}".format(self.cluster.UC.edges[activeEdge_id])
                _type = self.cluster.UC.edges[activeEdge_id].type 
                self.spinBox_type.setValue(_type)
                
            self.statusBar().showMessage(msg, 2000)
            if self.TEXT_MODE:
                print(msg)
                    
    def selectEdgeSignal_slot(self, activeEdge_id):
        '''Process selecting edge signal'''
        activeItem = self.listEdges_idToItem[activeEdge_id]
        self.listEdges.setCurrentItem(activeItem)
        
    def change_textMode(self, _bool):
        '''turn on/off printing actions into terminal'''
        self.TEXT_MODE = _bool
        self.gee.display_report = _bool
        msg = " displaying actions in terminal is turned {}".format("on" if _bool else "off")
        self.statusBar().showMessage(msg, 2000)
        print(msg)
 
    def getFileLabelText(self):
        '''Returns the label string of the xml library file'''
        
        if self.fileNameXML is None:
            return "None"
        else:
            fileName = os.path.basename(self.fileNameXML)
            dirName = os.path.basename(os.path.dirname(self.fileNameXML))
            return os.path.join("...", dirName, fileName)

    def importXMLdlg_callback(self):
        '''when import acttion is activated'''
        
        output = QFileDialog.getOpenFileName(self, 
                               'Open xml library containing Lattice Graph',
                               filter = "XML files (*.xml);;All files (*.*)")
        path = getPathString(output)
        if path != "":
            self.importXML_fromFile(path)
                
    def importCryst_callback(self):
        '''import crystal providing lattice and unit cell parameters'''
        self.dlgImportCryst = DialogImportCryst(self)
        self.dlgImportCryst.show()

    def saveXML_callback(self):
        '''save changes to lattice graph xml library file'''
        
        if self.fileNameXML == None: 
            self.saveXML_as_callback()
        else:
            self.exporter = ExportXML(self.gee.cluster.lattice,
                                      self.gee.cluster.UC,
                                      self.LATTICEGRAPH_name)
            self.exporter.export_to_lib(self.fileNameXML)

    def saveXML_as_callback(self):
        '''save lattice graph to xml library file'''
        
        dialog = DialogExportLG(self, self.LATTICEGRAPH_name, 
                              self.cluster.lattice.atrib["BOUNDARY"])
        if dialog.exec_():
            
            self.LATTICEGRAPH_name = str(dialog.lineEdit_LGname.text())
            self.gee.cluster.lattice.atrib["BOUNDARY"]= \
                                str(dialog.comboBox_boundary.currentText())
                        
            output = QFileDialog.getSaveFileName(self, filter="XML files (*.xml)")
            path = getPathString(output)
            # if not canceled
            if path != '':
                self.fileNameXML = path
                self.exporter = ExportXML(self.gee.cluster.lattice,
                                          self.gee.cluster.UC,
                                          self.LATTICEGRAPH_name)
                self.exporter.export_to_lib(self.fileNameXML)
                self.label_fileNameXML.setText("XML library file:  "+self.getFileLabelText())

    def exportIMG_callback(self):
        '''Savve image of the Heisenberg model (lattice graph)'''
                
        output = QFileDialog.getSaveFileName(self,caption='Save model image',
                                        filter="Images (*.png *.xpm *.jpg);;All files (*.*)")
        path = getPathString(output)
        if path != '':
            self.exportIMG(path)

    def exportIMG(self, path):
        '''Savve image of the Heisenberg model (lattice graph)'''
                
        self.canvas.print_figure(path, dpi=self.dpi, bbox_inches='tight', pad_inches=0)
        self.statusBar().showMessage('Saved to %s' % path, 2000)
    
    def exportAnim_callback(self):
        '''animate lattice graph mpl_pane and open animation manager'''
        
        self.dlgExportAnim = QDialogAnimManager(self.ax)
        self.dlgExportAnim.show()
        # disable animated GraphEdgeEditor artists
        self.gee.sc_active.set_visible(False)
        self.gee.new_edge.set_visible(False)
        # enabele animated GraphEdgeEditor artists
        self.dlgExportAnim.closed.connect(self.gee.sc_active.set_visible)
        self.dlgExportAnim.closed.connect(self.gee.new_edge.set_visible)
        
    def quit_callback(self):
        self.close()    
    
    def editXML_callback(self):
        ''' open lattice graph xml code editor'''
        self.dlgEditXML = DialogEditXML(self)
        self.dlgEditXML.show()
        if self.TEXT_MODE:            
            print(" open lattice graph xml code editor")
    
    def addSimEdges_callback(self):
        '''search for and add edges that have the same length as selected one'''
        
        if self.gee.e_active_ind is None:
            self.msb_noActiveEdge.exec_()            
        else:
            self.gee.searchActiveDistEdge_callback()

    def addDistEdges_callback(self):
        '''opens edge length manipulation manager'''
        self.gee.select_edge(None)
        self.selectEdgeSignal_slot(None)
        self.dlgDistSearch = DialogDistSearch(self)
        self.dlgDistSearch.show()

    def menuChangeType_callback(self):
        '''change selected edge type'''
        if self.gee.e_active_ind is None:
            self.msb_noActiveEdge.exec_()            
        else:
            self.dlg = DialogChangeEdgeType(self)
            self.dlg.show()
 
    def delteEdge_callback(self):
        '''delete selected edge'''        

        if self.gee.e_active_ind is None:
            self.msb_noActiveEdge.exec_()            
        else:
            self.gee.delete_active_edge_callback()
    
    def preferences_callback(self):
        '''Calls preference dialog'''
        
        self.dlgPref = MyDialogPreferences(parent = self)
        self.dlgPref.applySignal.connect(self.applyPref_callback)
        self.arrowsVisibleChanged.connect(self.dlgPref.prefWidget.checkBox_arrows.setChecked)
        self.latticeVisibleChanged.connect(self.dlgPref.prefWidget.checkBox_lattice.setChecked)
        self.dlgPref.show()
    
    def applyPref_callback(self):
        '''when apply button is cklicked in DialogPreferences'''
        
        self.gee.initialize_theme(self.CURRENT_THEME)
        self.gee.set_artists_properties()
        
    def about_callback(self):
        '''display app help'''
        self.msg = QMessageBox()
        self.msg.setIcon(QMessageBox.Information)
        self.msg.setTextFormat(Qt.RichText)

        text = '''
<b>Lattice graph designer 1.0a1</b>
<br>
Copyright &copy; 2017, Ivan Luchko and Project Contributors 
<br>
Licensed under the terms of the MIT License 
<br><br>
Lattice graph designer is a tool which allows to visualize and create 
a lattice graph model using the intuitive GUI and interactive 3D drag-and-drop 
graph manipulation pane. 
<br><br>
It was primarily created for the 
<a href="http://alps.comp-phys.org">ALPS project</a> to deal with a lattice graph of the 
<a href="https://en.wikipedia.org/wiki/Heisenberg_model_(quantum)">Heisenberg model</a> 
defined in <a href="http://alps.comp-phys.org/mediawiki/index.php/Tutorials:LatticeHOWTO">
ALPS xml graph format</a>.
<br><br>
Support of the other formats and projects can be extended.
<br><br>
For bug reports and feature requests, please go to our 
<a href="https://github.com/luchko/latticegraph_designer">Github website</a>.
'''
        
        self.msg.setText(text)
        self.msg.setWindowTitle("About Lattice graph designer")
        self.msg.setStandardButtons(QMessageBox.Ok)
        self.msg.exec_()
        
    def doc_callback(self):
        '''open documentation'''
        webbrowser.open_new_tab("https://latticegraph-designer.readthedocs.io")
예제 #45
0
파일: plot.py 프로젝트: NortySpock/artview
class Display(QtGui.QMainWindow):
    '''Class that plots a Radar structure using pyart.graph'''

    def __init__(self, Vradar, Vfield, Vtilt, airborne=False, rhi=False, name="Display", parent=None):
        '''Initialize the class to create the interface'''
        super(Display, self).__init__(parent)
        self.parent = parent
        self.name = name
        self.setWindowTitle(name)
        
        #XXX set up signal, so that DISPLAY can react to external (or internal) changes in radar,field and tilt
        #XXX radar,field and tilt are expected to be Core.Variable instances
        #XXX I use the capital V so people remember using ".value"
        self.Vradar = Vradar
        QtCore.QObject.connect(Vradar,QtCore.SIGNAL("ValueChanged"),self.NewRadar)
        self.Vfield = Vfield
        QtCore.QObject.connect(Vfield,QtCore.SIGNAL("ValueChanged"),self.NewField)
        self.Vtilt = Vtilt
        QtCore.QObject.connect(Vtilt,QtCore.SIGNAL("ValueChanged"),self.NewTilt)
        
        self.airborne = airborne
        self.rhi = rhi
        
        # Set size of plot
        self.XSIZE = PPI_XSIZE
        self.YSIZE = PPI_YSIZE
        self.XRNG = PPI_XRNG
        self.YRNG = PPI_YRNG
        if self.airborne:
            self.XSIZE = AIR_XSIZE
            self.YSIZE = AIR_YSIZE
            self.XRNG = AIR_XRNG
            self.YRNG = AIR_YRNG
        if self.rhi:
            self.XSIZE = RHI_XSIZE
            self.YSIZE = RHI_YSIZE
            self.XRNG = RHI_XRNG
            self.YRNG = RHI_YRNG
        
        # Set plot title and colorbar units to defaults
        self.title = None
        self.units = None
        # Initialize limits
        self._initialize_limits()
            
        # Set the default range rings
        self.RngRingList = ["None", "10 km", "20 km", "30 km", "50 km", "100 km"]
        self.RngRing = False
        
        # Find the PyArt colormap names
#        self.cm_names = pyart.graph.cm._cmapnames
        self.cm_names = [m for m in cm.datad if not m.endswith("_r")]
        self.cm_names.sort()
  
        # Create a figure for output
        self._set_fig_ax(nrows=1, ncols=1)
        
        # Initiate no tool useage
        self.ToolSelect = "No Tools" #XXX this is problably not the right way of doing this
        
        # Launch the GUI interface
        self.LaunchGUI() #XXX almost empty
        
        self.NewRadar(None, None) #XXX initialise radar
        
        self.show()
        
        self.pickPoint = self.fig.canvas.mpl_connect('button_press_event', self.onPick)

        
    # Allow advancement via left and right arrow keys
    # and tilt adjustment via the Up-Down arrow keys
    def keyPressEvent(self, event):
        if event.key()==QtCore.Qt.Key_Up:
            self.TiltSelectCmd(self.Vtilt.value + 1) #XXX Display control de tilt, but not the file
        elif event.key()==QtCore.Qt.Key_Down:
            self.TiltSelectCmd(self.Vtilt.value - 1) #XXX Display control de tilt, but not the file
        else:
            if self.parent==None:
                QtGui.QWidget.keyPressEvent(self, event)
            else:
                self.parent.keyPressEvent(event) #XXX send event to parent to handel it, I consider not having a pygt form of doing this a limitation
            
    def onPick(self, event):
        '''Get value at the point selected by mouse click'''
        xdata = event.xdata # get event x location
        ydata = event.ydata # get event y location
        az = np.arctan2(xdata, ydata)*180./np.pi
        radar = self.Vradar.value #keep equantions clean
        if az < 0:
            az = az + 360.
        rng = np.sqrt(xdata*xdata+ydata*ydata)
        azindex = np.argmin(np.abs(radar.azimuth['data'][radar.sweep_start_ray_index['data'][self.Vtilt.value]:radar.sweep_end_ray_index['data'][self.Vtilt.value]]-az))+radar.sweep_start_ray_index['data'][self.Vtilt.value]
        rngindex = np.argmin(np.abs(radar.range['data']-rng*1000.))
        msg = 'x = %4.2f, y = %4.2f, Azimuth = %4.2f deg., Range = %4.2f km, %s = %4.2f %s'\
        %(xdata, ydata, radar.azimuth['data'][azindex], radar.range['data'][rngindex]/1000., self.Vfield.value, radar.fields[self.Vfield.value]['data'][azindex][rngindex], self.units)
        self.statusBar().showMessage(msg)

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(8)
        
        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
#        self.statusBar()
        
        self.central_widget.setLayout(self.layout)
        #self.setLayout(self.layout)
        # Create the Tilt buttons
        #self.CreateTiltWidget()
        
        # Create the Tools ComboBox
#        self.toolsBoxUI()
        
        self.addButtons()
                    
    ########################
    # Button methods #
    ######################## 
    def addButtons(self):
        '''If not BASIC mode, then add functionality buttons'''
        # Create the button controls
        limsb = QtGui.QPushButton("Adjust Limits")
        limsb.setToolTip("Set data, X, and Y range limits")
#        limsb.clicked.connect(self.showLimsDialog)
        titleb = QtGui.QPushButton("Title")
        titleb.setToolTip("Change plot title")
        titleb.clicked.connect(self._title_input)
        unitsb = QtGui.QPushButton("Units")
        unitsb.setToolTip("Change units string")
        unitsb.clicked.connect(self._units_input)
        tiltsb = QtGui.QPushButton("Tilt Select")
        tiltsb.setToolTip("Choose tilt elevation angle")
        tiltsb.clicked.connect(self._open_tiltbuttonwindow)
        
        self.layout.addWidget(limsb, 0, 0)
#        self.layout.addWidget(self.toolsBox, 0, 1)
        self.layout.addWidget(titleb, 0, 2)
        self.layout.addWidget(unitsb, 0, 3)
        self.layout.addWidget(tiltsb, 0, 4)
        
    #############################
    # Functionality methods #
    #############################
            
    def _lims_input(self, entry):
        '''Retrieve new limits input'''
        if entry['dmin'] is not None:
            self.limits['vmin'] = entry['dmin']
        if entry['dmax'] is not None:
            self.limits['vmax'] = entry['dmax']
        if entry['xmin'] is not None:
            self.limits['xmin'] = entry['xmin']
        if entry['xmax'] is not None:
            self.limits['xmax'] = entry['xmax']
        if entry['ymin'] is not None:
            self.limits['ymin'] = entry['ymin']
        if entry['ymax'] is not None:
            self.limits['ymax'] = entry['ymax']
        self._update_plot()

    def _title_input(self):
        '''Retrieve new plot title'''
        if self.title is None:
            old_val = ''
        else:
            old_val = self.title
        val, entry = QtGui.QInputDialog.getText(self, "Plot Title", \
                  "Title:", 0, old_val)
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units'''
        if self.units is None:
            old_val = ''
        else:
            old_val = self.units
        val, entry = QtGui.QInputDialog.getText(self, "Plot Units", \
                  "Units:", 0, old_val)
        if entry is True:
            self.units = val
            self._update_plot()
            
    def _open_tiltbuttonwindow(self):
        '''Open a TiltButtonWindow instance'''
        self.tiltbuttonwindow = TiltButtonWindow(self.Vradar, self.Vtilt, \
                            name=self.name+" Tilt Selection", parent=self.parent)
        
    ########################
    # Selectionion methods #
    ########################

    def NewRadar(self,variable,value):
        # In case the flags were not used at startup
        self._check_file_type()
        self._set_figure_canvas()

        # Get the tilt angles
        self.rTilts = self.Vradar.value.sweep_number['data'][:]
        # Get field names
        self.fieldnames = self.Vradar.value.fields.keys()

        # Set up the menus associated with scanning ground radars
        if self.airborne or self.rhi:
            pass
        else:
            pass
        self.units = None
        self.title = None
        self._update_plot()

    def NewField(self,variable,value):
        self._initialize_limits()
        self.units = None
        self._update_plot()
    
    def NewTilt(self,variable,value):
        self._update_plot()


    def TiltSelectCmd(self, ntilt):
        '''Captures a selection and redraws the field with new tilt'''
        print ntilt
        self.Vtilt.change(ntilt)
        #XXX tilt is changed and signal sended, so this and other classes do what they need to do


    def FieldSelectCmd(self, nombre):
        '''Captures a selection and redraws the new field'''
        self.Vfield.change(nombre)


    def RngRingSelectCmd(self, ringSel):
        '''Captures selection and redraws the field with range rings'''
        if ringSel is "None":
            self.RngRing = False
        else:
            self.RngRing = True
            # Find the unambigous range of the radar
            try:
                unrng = int(self.radar.instrument_parameters['unambiguous_range']['data'][0]/1000)
            except:
                unrng = int(self.limits['xmax'])
            
            # Set the step
            if ringSel == '10 km':
                ringdel = 10
            if ringSel == '20 km':
                ringdel = 20
            if ringSel == '30 km':
                ringdel = 30
            if ringSel == '50 km':
                ringdel = 50
            if ringSel == '100 km':
                ringdel = 100
                
            # Calculate an array of range rings
            self.RNG_RINGS = range(ringdel, unrng, ringdel)
        
        self._update_plot()
        
    def cmapSelectCmd(self, cm_name):
        '''Captures selection of new cmap and redraws'''
        self.CMAP = cm_name
        self._update_plot()
        
        
    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self, nrows=1, ncols=1):
        '''Set the figure and axis to plot to'''
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        xwidth = 0.7
        yheight = 0.7 * float(self.YSIZE)/float(self.XSIZE)
        self.ax = self.fig.add_axes([0.2, 0.2, xwidth, yheight])
        self.cax = self.fig.add_axes([0.2,0.10, xwidth, 0.02])
        
        # We want the axes cleared every time plot() is called
        #self.axes.hold(False)
        
    def _set_fig_ax_rhi(self):
        '''Change figure size and limits if RHI'''
        if self.rhi:
            self.XSIZE = RHI_XSIZE
            self.YSIZE = RHI_YSIZE
            self.limits['ymin'] = RHI_YRNG[0]
            self.limits['ymax'] = RHI_YRNG[1]
        if self.airborne:
            self.XSIZE = AIR_XSIZE
            self.YSIZE = AIR_YSIZE
            self.limits['xmin'] = AIR_XRNG[0]
            self.limits['xmax'] = AIR_XRNG[1]
            self.limits['ymin'] = AIR_YRNG[0]
            self.limits['ymax'] = AIR_YRNG[1]
        self.fig.set_size_inches(self.XSIZE, self.YSIZE)
        self._set_fig_ax()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 7, 6)

    def _update_plot(self):
        '''Renew the plot'''
        # This is a bit of a hack to ensure that the viewer works with files
        # withouth "standard" output as defined by PyArt
        # Check to see if the field 'reflectivity' exists for the initial open
        self._check_default_field()
    
        # Create the plot with PyArt RadarDisplay 
        # Always intitiates at lowest elevation angle
        self.ax.cla()

        # Reset to default title if user entered nothing w/ Title button
        if self.title == '':
            self.title = None
        
        # If Zoom/Pan selected, Set up the zoom/pan functionality
        if self.ToolSelect == "Zoom/Pan":
            scale = 1.1
            self.zp = ZoomPan(self.ax, self.limits, base_scale = scale)
            #figZoom = self.zp.zoom()
            #figPan = self.zp.pan_factory(self.limits)
            self.zp.connect()
        
        if self.airborne:
            self.display = pyart.graph.RadarDisplay_Airborne(self.Vradar.value)
            
            self.plot = self.display.plot_sweep_grid(self.Vfield.value, \
                                vmin=self.limits['vmin'], vmax=self.limits['vmax'],\
                                colorbar_flag=False, cmap=self.CMAP,\
                                ax=self.ax, title=self.title)
            self.display.set_limits(xlim=(self.limits['xmin'], self.limits['xmax']),\
                                    ylim=(self.limits['ymin'], self.limits['ymax']),\
                                    ax=self.ax)
            self.display.plot_grid_lines()
        else:
            self.display = pyart.graph.RadarDisplay(self.Vradar.value)
            if self.Vradar.value.scan_type != 'rhi':
                # Create Plot
                if self.Vtilt.value < len(self.rTilts):
                    pass
                else:
                    self.Vtilt.change(0)
                self.plot = self.display.plot_ppi(self.Vfield.value, self.Vtilt.value,\
                                vmin=self.limits['vmin'], vmax=self.limits['vmax'],\
                                colorbar_flag=False, cmap=self.CMAP,\
                                ax=self.ax, title=self.title)
                # Set limits
                self.display.set_limits(xlim=(self.limits['xmin'], self.limits['xmax']),\
                                        ylim=(self.limits['ymin'], self.limits['ymax']),\
                                        ax=self.ax)
                # Add range rings
                if self.RngRing:
                    self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)
                # Add radar location
                self.display.plot_cross_hair(5., ax=self.ax)
            else:
                self.plot = self.display.plot_rhi(self.Vfield.value, self.Vtilt.value,\
                                vmin=self.limits['vmin'], vmax=self.limits['vmax'],\
                                colorbar_flag=False, cmap=self.CMAP,\
                                ax=self.ax, title=self.title)
                self.display.set_limits(xlim=(self.limits['xmin'], self.limits['xmax']),\
                                        ylim=(self.limits['ymin'], self.limits['ymax']),\
                                        ax=self.ax)
                # Add range rings
                if self.RngRing:
                    self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)
        
        norm = mlabNormalize(vmin=self.limits['vmin'],\
                                           vmax=self.limits['vmax'])
        self.cbar=mlabColorbarBase(self.cax, cmap=self.CMAP,\
                                                norm=norm, orientation='horizontal')
        # colorbar - use specified units or default depending on
        # what has or has not been entered
        if self.units is None or self.units == '':
            try:
                self.units = self.Vradar.value.fields[self.field]['units']
            except:
                self.units = ''
        self.cbar.set_label(self.units)
        
        print "Plotting %s field, Tilt %d" % (self.Vfield.value, self.Vtilt.value+1)
        self.canvas.draw()
 
    #########################
    # Get and check methods #
    #########################
    def _initialize_limits(self):
        field = self.Vfield.value
        if field == 'reflectivity':
            self.vminmax = (Z_LIMS[0], Z_LIMS[1])
            self.CMAP = 'gist_ncar'
        elif field == 'DBZ' or field == 'DBZH':
            self.vminmax = (Z_LIMS[0], Z_LIMS[1])
            self.CMAP = 'gist_ncar'
        elif field == 'velocity':
            self.vminmax = (VR_LIMS[0], VR_LIMS[1])
            self.CMAP = 'RdBu_r'
        elif field == 'VEL':
            self.vminmax = (VR_LIMS[0], VR_LIMS[1])
            self.CMAP = 'RdBu_r'
        elif field == 'differential_reflectivity':
            self.vminmax = (ZDR_LIMS[0], ZDR_LIMS[1])
            self.CMAP = 'RdYlBu_r'
        elif field == 'cross_correlation_ratio':
            self.vminmax = (RHO_HV_LIMS[0], RHO_HV_LIMS[1])
            self.CMAP = 'cool'
        elif field == 'differential_phase':
            self.vminmax = (KDP_LIMS[0], KDP_LIMS[1])
            self.CMAP = 'YlOrBr'
        elif field == 'normalized_coherent_power':
            self.vminmax = (NCP_LIMS[0], NCP_LIMS[1])
            self.CMAP = 'jet'
        elif field == 'spectrum_width':
            self.vminmax = (SW_LIMS[0], SW_LIMS[1])
            self.CMAP = 'gist_ncar'
        elif field == 'specific_differential_phase':
            self.vminmax = (PHIDP_LIMS[0], PHIDP_LIMS[1]) 
            self.CMAP = 'RdBu_r'
        elif field == 'total_power':
            self.vminmax = (TP_LIMS[0], TP_LIMS[1])
            self.CMAP = 'jet'
           
        limit_strs = ('vmin', 'vmax', 'xmin', 'xmax', 'ymin', 'ymax')
        self.limits = {}
        
        # Now pull the default values
        self.limits['vmin'] = self.vminmax[0]
        self.limits['vmax'] = self.vminmax[1]
        self.limits['xmin'] = self.XRNG[0]
        self.limits['xmax'] = self.XRNG[1]
        self.limits['ymin'] = self.YRNG[0]
        self.limits['ymax'] = self.YRNG[1]
        
# #    def _build_cmap_dict(self):
# #        self.cmap_dict = {}
# #        self.cmap_dict['gist_ncar'] = matcm.get_cmap(name='gist_ncar')
# #        self.cmap_dict['RdBu_r'] = matcm.get_cmap(name='RdBu_r')
# #        self.cmap_dict['RdYlBu_r'] = matcm.get_cmap(name='RdYlBu_r
# #        self.cmap_dict['cool'] = matcm.get_cmap(name='cool
# #        self.cmap_dict['YlOrBr'] = matcm.get_cmap(name='YlOrBr
# #        self.cmap_dict['jet'] = matcm.get_cmap(name='jet
# #        self.cmap_dict['
# #        self.cmap_dict['
        
    def _check_default_field(self):
        '''Hack to perform a check on reflectivity to make it work with 
        a larger number of files
        This should only occur upon start up with a new file'''
        if self.Vfield.value == 'reflectivity':
            if self.Vfield.value in self.fieldnames:
                pass
            elif 'CZ' in self.fieldnames:
                self.Vfield.change('CZ')
            elif 'DZ' in self.fieldnames:
                self.Vfield.change('DZ')
            elif 'dbz' in self.fieldnames:
                self.Vfield.change('dbz')
            elif 'DBZ' in self.fieldnames:
                self.Vfield.change('DBZ')
            elif 'dBZ' in self.fieldnames:
                self.Vfield.change('dBZ')
            elif 'Z' in self.fieldnames:
                self.Vfield.change('Z')
            elif 'DBZ_S'in self.fieldnames:
                self.Vfield.change('DBZ_S')
            elif 'reflectivity_horizontal'in self.fieldnames:
                self.Vfield.change('reflectivity_horizontal')

                
    def _check_file_type(self):
        '''Check file to see if the file is airborne or rhi'''
        if self.Vradar.value.scan_type != 'rhi':
            pass
        else:
            try:
                (self.Vradar.value.metadata['platform_type'] == 'aircraft_tail') or \
                (self.Vradar.value.metadata['platform_type'] == 'aircraft')
                self.airborne = True
            except:
                self.rhi = True
            
            self._set_fig_ax_rhi()
 
    ########################
    # Warning methods #
    ########################
    def _ShowWarning(self, msg):
        '''Show a warning message'''
        flags = QtGui.QMessageBox.StandardButton()
        response = QtGui.QMessageBox.warning(self, "Warning!",
                                             msg, flags)
        if response == 0:
            print msg
        else:
            print "Warning Discarded!"
 
    ########################
    # Image save methods #
    ########################
    def _quick_savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display'''
        PNAME = self.display.generate_filename(self.Vfield.value, self.Vtilt.value, ext=IMAGE_EXT)
        print "Creating "+ PNAME
        
    def _savefile(self, PTYPE=IMAGE_EXT):
        PBNAME = self.display.generate_filename(self.Vfield.value, self.Vtilt.value, ext=IMAGE_EXT)
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(self, 'Save file', '', file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusBar().showMessage('Saved to %s' % path)
예제 #46
0
class PointsDisplay(Component):
    '''
    Class to create a display plot, using data from a Points instance.
    '''

    Vpoints = None  #: see :ref:`shared_variable`
    Vfield = None  #: see :ref:`shared_variable`
    Vlims = None  #: see :ref:`shared_variable`
    Vcmap = None  #: see :ref:`shared_variable`

    @classmethod
    def guiStart(self, parent=None):
        '''Graphical interface for starting this class'''
        kwargs, independent = \
            common._SimplePluginStart("PointsDisplay").startDisplay()
        kwargs['parent'] = parent
        return self(**kwargs), independent

    def __init__(self, Vpoints=None, Vfield=None, Vlims=None, Vcmap=None,
                 plot_type="histogram", name="PointsDisplay", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        [Optional]
        Vpoints : :py:class:`~artview.core.core.Variable` instance
            Points signal variable. If None start new one with None.
        Vfield : :py:class:`~artview.core.core.Variable` instance
            Field signal variable. If None start new one with empty string.
        Vlims : :py:class:`~artview.core.core.Variable` instance
            Limits signal variable.
            A value of None will instantiate a limits variable.
        Vcmap : :py:class:`~artview.core.core.Variable` instance
            Colormap signal variable.
            A value of None will instantiate a colormap variable.
        plot_type : str
            Type of plot to produce (e.g. histogram, statistics, table).
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        '''
        super(PointsDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)

        if Vpoints is None:
            self.Vpoints = Variable(None)
        else:
            self.Vpoints = Vpoints

        if Vfield is None:
            self.Vfield = Variable('')
        else:
            self.Vfield = Vfield

        if Vlims is None:
            self.Vlims = Variable({})
        else:
            self.Vlims = Vlims

        if Vcmap is None:
            self.Vcmap = Variable(None)
        else:
            self.Vcmap = Vcmap

        self.sharedVariables = {"Vpoints": self.NewPoints,
                                "Vfield": self.NewField,
                                "Vlims": self.NewLims,
                                "Vcmap": self.NewCmap,
                                }

        # Connect the components
        self.connectAllVariables()

        # Set plot title and colorbar units to defaults
        self.title = self._get_default_title()
        self.units = self._get_default_units()

        # Find the PyArt colormap names
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Set up Default limits and cmap
        if Vcmap is None:
            self._set_default_cmap(strong=False)
        if Vlims is None:
            self._set_default_limits(strong=False)

        self.plot_type = None
        self.changePlotType(plot_type)

        self.show()

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QVBoxLayout()

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add Menu
        self.addStandardMenu()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    def addStandardMenu(self):
        '''Add Standard Menus.'''
        self.menubar = self.menuBar()

        self.filemenu = self.menubar.addMenu('File')

        openCSV = self.filemenu.addAction('Open Tabular Data')
        openCSV.setStatusTip('Open a Region Data CSV file')
        openCSV.triggered.connect(self.openTable)

        saveCSV = self.filemenu.addAction('Save Tabular Data')
        saveCSV.setStatusTip('Save a Region Data CSV file')
        saveCSV.triggered.connect(self.saveTable)

        self.plotTypeMenu = self.menubar.addMenu('Plot Type')

        hist = self.plotTypeMenu.addAction('Histogram')
        hist.setStatusTip('Plot histogram of Data ')
        hist.triggered.connect(lambda: self.changePlotType('histogram'))

        stats = self.plotTypeMenu.addAction('Statistics')
        stats.setStatusTip('Show basic statistics of Data')
        stats.triggered.connect(lambda: self.changePlotType('statistics'))

        table = self.plotTypeMenu.addAction('Table')
        table.setStatusTip('Show data in a Table')
        table.triggered.connect(lambda: self.changePlotType('table'))

        self.displayMenu = self.menubar.addMenu('Display')

    ##################################
    # User display interface methods #
    ##################################

    #############################
    # Functionality methods #
    #############################

    def changePlotType(self, plot_type):

        try:
            if self.plot_type == 'histogram':
                self.layout.removeWidget(self.canvas)
                self.canvas.hide()
            elif self.plot_type == 'statistics':
                self.layout.removeWidget(self.statistics)
                self.statistics.close()
            elif self.plot_type == 'table':
                self.layout.removeWidget(self.table)
                self.table.close()
        except:
            pass

        self.plot_type = plot_type
        self.displayMenu.clear()

        if plot_type == 'histogram':
            self._fill_histogram_menu()
            # Add the widget to the canvas
            self.layout.addWidget(self.canvas, 0)
            self.canvas.show()
        elif plot_type == 'statistics':
            pass
        elif plot_type == 'table':
            pass

        self._update_plot()

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(
            self.Vlims.value, self.Vcmap.value, self.name)

        if change == 1:
            self.Vcmap.change(cmap)
            self.Vlims.change(limits)

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog_with_reset(
            self.title, "Plot Title", "Title:", self._get_default_title())
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog_with_reset(
            self.units, "Plot Units", "Units:", self._get_default_units())
        if entry is True:
            self.units = val
            self._update_plot()

    def _fill_histogram_menu(self):
        '''Create the Display Options Button menu.'''

        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = self.displayMenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
#        dispTitle = dispmenu.addAction("Change Title")
#        dispTitle.setToolTip("Change plot title")
#        dispUnit = dispmenu.addAction("Change Units")
#        dispUnit.setToolTip("Change units string")
        dispSaveFile = self.displayMenu.addAction("Save Image")
        dispSaveFile.setShortcut("Ctrl+S")
        dispSaveFile.setStatusTip("Save Image using dialog")
#        dispHelp = self.displayMenu.addAction("Help")

        dispLimits.triggered.connect(self._open_LimsDialog)
#        dispTitle.triggered.connect(self._title_input)
#        dispUnit.triggered.connect(self._units_input)
        dispSaveFile.triggered.connect(self._savefile)
#        dispHelp.triggered.connect(self._displayHelp) #XXX help is out dated

    def _displayHelp(self):
        text = (
            "<b>Using the PlotPoints Display</b><br><br>"
            "<i>Purpose</i>:<br>"
            "Display a plot of selected points.<br><br>"
            "The limits dialog is a common format that allows the user "
            "change:<br>"
            "<i>X and Y limits<br>"
            "Data limits</i><br>"
            "However, not all plots take each argument.<br>"
            "For example, a simple line plot has no data min/max data "
            "value.<br>")

        common.ShowLongText(text, set_html=True)

    def NewPoints(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vradar <artview.core.core.Variable>`.

        This will:

        * Update fields and tilts lists and MenuBoxes
        * Check radar scan type and reset limits if needed
        * Reset units and title
        * If strong update: update plot
        '''
        # test for None
        if self.Vpoints.value is None:
            # self.fieldBox.clear()
            return

        # Get field names
        self.fieldnames = self.Vpoints.value.fields.keys()

#        self._fillFieldBox()

        self.units = self._get_default_units()
        self.title = self._get_default_title()
        if strong:
            self._update_plot()
#            self._update_infolabel()

    def NewField(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vfield <artview.core.core.Variable>`.

        This will:

        * Reset colormap
        * Reset units
        * Update fields MenuBox
        * If strong update: update plot
        '''
        self._set_default_cmap(strong=False)
        self.units = self._get_default_units()
        self.title = self._get_default_title()
#        idx = self.fieldBox.findText(value)
#        self.fieldBox.setCurrentIndex(idx)
        if strong:
            self._update_plot()
#            self._update_infolabel()

    def NewLims(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlims <artview.core.core.Variable>`.

        This will:

        * If strong update: update axes
        '''
        if strong:
            self._update_axes()

    def NewCmap(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vcmap <artview.core.core.Variable>`.

        This will:

        * If strong update: update plot
        '''
        if strong:
            pass
            # self._update_plot()

    ########################
    # Selectionion methods #
    ########################

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 5
        self.YSIZE = 5
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''

        if self.Vpoints.value is None:
            return

        # Create the plot with PyArt PlotDisplay
        self.ax.cla()  # Clear the plot axes

        # Reset to default title if user entered nothing w/ Title button

        colorbar_flag = False

        points = self.Vpoints.value
        field = self.Vfield.value
        cmap = self.Vcmap.value

        if field not in points.fields.keys():
            self.canvas.draw()
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(255,0,0,255);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.showMessage("Field not Found", msecs=5000)
            return
        else:
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(0,0,0,0);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.clearMessage()

        if self.plot_type == "histogram":
            self.plot = self.ax.hist(
                points.fields[field]['data'], bins=25,
                range=(cmap['vmin'], cmap['vmax']),
                figure=self.fig)
            self.ax.set_ylabel("Counts")

            # If limits exists, update the axes otherwise retrieve
            # self._update_axes()
            self._update_limits()

            # If the colorbar flag is thrown, create it
            if colorbar_flag:
                # Clear the colorbar axes
                self.cax.cla()
                self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
                norm = mlabNormalize(vmin=cmap['vmin'],
                                     vmax=cmap['vmax'])
                self.cbar = mlabColorbarBase(self.cax, cmap=self.cm_name,
                                             norm=norm,
                                             orientation='horizontal')
                # colorbar - use specified units or default depending on
                # what has or has not been entered
                self.cbar.set_label(self.units)

            self.canvas.draw()

        elif self.plot_type == 'statistics':
            if (self.Vpoints.value is None or
                self.Vfield.value not in self.Vpoints.value.fields):
                common.ShowWarning("Please select Region and Field first")
            else:
                points = self.Vpoints.value
                field = self.Vfield.value
                SelectRegionstats = common._array_stats(
                    points.fields[field]['data'])
                text = "<b>Basic statistics for the selected Region</b><br><br>"
                for stat in SelectRegionstats:
                    text += ("<i>%s</i>: %5.2f<br>" %
                             (stat, SelectRegionstats[stat]))
                self.statistics = QtGui.QDialog()
                layout = QtGui.QGridLayout(self.statistics)
                self.statistics = QtGui.QTextEdit("")
                self.statistics.setAcceptRichText(True)
                self.statistics.setReadOnly(True)
                self.statistics.setText(text)
                self.layout.addWidget(self.statistics, 0)

        elif self.plot_type == "table":
            if self.Vpoints.value is not None:
                # Instantiate Table
                self.table = common.CreateTable(self.Vpoints.value)
                self.layout.addWidget(self.table, 0)
                self.table.display()
                # Show the table
                self.table.show()
            else:
                common.ShowWarning("Please select or open Region first")

    def _update_axes(self):
        '''Change the Plot Axes.'''
        limits = self.Vlims.value
        self.ax.set_xlim(limits['xmin'], limits['xmax'])
        self.ax.set_ylim(limits['ymin'], limits['ymax'])
        self.canvas.draw()

    def _update_limits(self):
        limits = self.Vlims.value
        ax = self.ax.get_xlim()
        limits['xmin'] = ax[0]
        limits['xmax'] = ax[1]
        ax = self.ax.get_ylim()
        limits['ymin'] = ax[0]
        limits['ymax'] = ax[1]
        self.Vlims.update()

    def _set_default_cmap(self, strong=True):
        ''' Set colormap to pre-defined default.'''
        cmap = pyart.config.get_field_colormap(self.Vfield.value)
        d = {}
        d['cmap'] = cmap
        lims = pyart.config.get_field_limits(self.Vfield.value,
                                             self.Vpoints.value)
        if lims != (None, None):
            d['vmin'] = lims[0]
            d['vmax'] = lims[1]
        else:
            d['vmin'] = -10
            d['vmax'] = 65
        self.Vcmap.change(d, False)

    def _set_default_limits(self, strong=True):
        ''' Set limits to pre-defined default.'''
        cmap = self.Vcmap.value
        d = {}
        d['xmin'] = cmap['vmin']
        d['xmax'] = cmap['vmax']
        d['ymin'] = 0
        d['ymax'] = 1000
        self.Vlims.change(d, False)

    def _get_default_title(self):
        '''Get default title.'''
        if (self.Vpoints.value is None or
            self.Vfield.value not in self.Vpoints.value.fields):
            return ''
        return 'Points Plot'
        # pyart.graph.common.generate_title(self.Vpoints.value,
        #                                  self.Vfield.value,
        #                                  0)

    def _get_default_units(self):
        '''Get default units for current radar and field.'''
        if self.Vpoints.value is not None:
            try:
                return self.Vpoints.value.fields[self.Vfield.value]['units']
            except:
                return ''
        else:
            return ''

    ########################
    # Image save methods #
    ########################

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', ' ', file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)

    def openTable(self):
        '''Open a saved table of SelectRegion points from a CSV file.'''
        path = QtGui.QFileDialog.getOpenFileName(
            self, 'Open File', '', 'CSV(*.csv)')
        if path == '':
            return
        points = read_points_csv(path)
        self.Vpoints.change(points)

    def saveTable(self):
        '''Save a Table of SelectRegion points to a CSV file.'''
        points = self.Vpoints.value
        if points is not None:
            fsuggest = ('SelectRegion_' + self.Vfield.value + '_' +
                        str(points.axes['x_disp']['data'][:].mean()) + '_' +
                        str(points.axes['y_disp']['data'][:].mean())+'.csv')
            path = QtGui.QFileDialog.getSaveFileName(
                self, 'Save CSV Table File', fsuggest, 'CSV(*.csv)')
            if not path.isEmpty():
                write_points_csv(path, points)
        else:
            common.ShowWarning("No gate selected, no data to save!")
예제 #47
0
파일: View.py 프로젝트: nomarkeu/SeisSol
class View(QWidget):

  def __init__(self, parent = None):
    super(View, self).__init__(parent)
    
    self.__watchdog = Watchdog.Watchdog()
    self.__watchdog.fileChanged.connect(self.refreshAll)

    self.figure = plt.figure()
    self.canvas = FigureCanvas(self.figure)
    self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)    
    toolbar = NavigationToolbar(self.canvas, self)
    
    self.navigationLayout = QHBoxLayout()
    
    layout = QHBoxLayout(self)
    self.navigations = []
    self.addNavigation(True)
    
    self.filters = [ Filters.Lowpass(), Filters.Deconvolve(), Filters.Rotate() ]
    filterLayout = QVBoxLayout()    
    for f in self.filters:
      filterLayout.addWidget(f)
      f.filterChanged.connect(self.plot)
    filterLayout.addStretch()
    
    addIcon = QIcon.fromTheme('list-add')
    addNaviButton = QPushButton(addIcon, 'Add navigation', self)
    addNaviButton.clicked.connect(self.addNavigation)
    
    self.maxFreq = QDoubleSpinBox(self)
    self.maxFreq.setValue(10.0)
    self.maxFreq.setVisible(False)
    self.maxFreq.valueChanged.connect(self.plot)
    spectrumIcon = QIcon.fromTheme('network-wireless')
    self.spectrum = QPushButton(spectrumIcon, 'Spectrum', self)
    self.spectrum.setCheckable(True)
    self.spectrum.clicked.connect(self.plot)
    self.spectrum.toggled.connect(self.maxFreq.setVisible)
    self.diff = QPushButton('Diff', self)
    self.diff.setCheckable(True)
    self.diff.clicked.connect(self.plot)
    self.diff.clicked.connect(self.spectrum.setHidden)
    self.spectrum.toggled.connect(self.diff.setHidden)
    
    autoRefresh = QPushButton(QIcon.fromTheme('view-refresh'), 'Auto', self)
    autoRefresh.setCheckable(True)
    autoRefresh.clicked.connect(self.__watchdog.toggle)
    
    saveAll = QPushButton(QIcon.fromTheme('document-save'), '', self)
    saveAll.clicked.connect(self.savePlots)

    toolLayout = QHBoxLayout()
    toolLayout.addWidget(addNaviButton)
    toolLayout.addWidget(self.diff)
    toolLayout.addWidget(self.spectrum)
    toolLayout.addWidget(self.maxFreq)
    toolLayout.addWidget(autoRefresh)
    toolLayout.addWidget(saveAll)
    toolLayout.addWidget(toolbar)
    plotLayout = QVBoxLayout()
    plotLayout.addLayout(toolLayout)
    plotLayout.addWidget(self.canvas)
    layout.addLayout(self.navigationLayout)
    layout.addLayout(plotLayout)
    layout.addLayout(filterLayout)
    
  def addNavigation(self, noclose = False):
    navigation = Navigation.Navigation(noclose)
    navigation.activeItemChanged.connect(self.plot)
    navigation.folderChanged.connect(self.navigationFolderChanged)
    navigation.close.connect(self.closeNavigation)
    navigation.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum)
    self.navigationLayout.addWidget(navigation)
    self.navigations.append(navigation)

  def navigationFolderChanged(self, oldFolder, newFolder):
    self.__watchdog.removeFolder(oldFolder)
    self.__watchdog.addFolder(newFolder)
    
  def closeNavigation(self, widget):
    self.navigations.remove(widget)
    self.navigationLayout.removeWidget(widget)
    widget.deleteLater()
    self.plot()
    
  def refreshAll(self):
    for navigation in self.navigations:
        navigation.refreshFolder()

  def plot(self):
    wfc = [wf for nav in self.navigations for wf in nav.getActiveWaveforms()]
    for filt in self.filters:
      if filt.isChecked():
        for wf in wfc:
          filt.apply(wf)
          
    if self.diff.isChecked() and len(wfc) > 0:
      wf0 = wfc.pop()
      for nWf, wf in enumerate(wfc):
        wfc[nWf].subtract(wf0)

    names = set([name for wf in wfc for name in wf.waveforms.keys()])
    numPlots = len(names)

    self.figure.clear()
    if numPlots > 0:
      names = list(names)
      names.sort()

      numRows = math.ceil(math.sqrt(numPlots));
      numCols = math.ceil(numPlots / numRows)
      subplots = dict()
      for i in range(len(names)):
        subplots[ names[i] ] = self.figure.add_subplot(numRows, numCols, i+1)

      for nWf, wf in enumerate(wfc):
        for name, waveform in wf.waveforms.items():
          p = subplots[name]
          if self.spectrum.isChecked():
            n = len(waveform)
            dt = wf.time[1]-wf.time[0] # assume equally spaced samples
            f = scipy.fftpack.fftfreq(n, dt)
            W = dt * scipy.fftpack.fft(waveform)
            maxFreqIndices = numpy.argwhere(f > self.maxFreq.value())
            L = maxFreqIndices[0,0] if numpy.size(maxFreqIndices) > 0 else n/2
            p.loglog(f[1:L], numpy.absolute(W[1:L]), label=str(nWf))
            p.set_xlabel('f [Hz]')
          elif self.diff.isChecked():
            p.plot(wf.time, waveform, label='{}-0'.format(nWf+1))
            p.set_xlabel('t (s)')
          else:
            p.plot(wf.time, waveform, label=str(nWf))
            p.set_xlabel('t (s)')
          p.set_ylabel(name)

      self.figure.tight_layout()

    for i in range(len(names)):
      subplots[ names[i] ].legend(prop={'size':8}, frameon=False)
    self.canvas.draw()
  
  def savePlots(self):
    filetypes = self.canvas.get_supported_filetypes_grouped()
    defaultFiletype = self.canvas.get_default_filetype()
    filters = []
    selectedFilter = ''
    for name, extensions in sorted(filetypes.items()):
      filtr = '{0} ({1})'.format(name, ' '.join(['*.{0}'.format(ext) for ext in extensions]))
      if defaultFiletype in extensions:
        selectedFilter = filtr
      filters.append(filtr)
    fileName, filtr = QFileDialog.getSaveFileNameAndFilter(self, 'Choose a save location.', '', ';;'.join(filters), selectedFilter)
    fileName = os.path.splitext(str(fileName))[0]
    extension = re.search(r'\*(\.[a-zA-Z]+)', str(filtr)).group(1)
    
    maxRow = min([nav.numberOfRows() for nav in self.navigations])
    for row in range(maxRow):
      for nav in self.navigations:
        nav.selectWaveformAt(row)
      self.plot()
      self.canvas.print_figure('{0}{1:03}{2}'.format(fileName, row+1, extension))
예제 #48
0
class PlotDisplay(Component):
    '''
    Class to create a display plot, using data and a key for plot type.
    '''

    def __init__(self, data, ydata=None, plot_type=None,
                 title=None, xlabel=None, ylabel=None,
                 name="PlotDisplay", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        data : data array
            The data to be plotted.
        [Optional]
        plot_type : str
            Type of plot to produce (e.g. plot, barplot, etc).
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        Notes
        -----
        This class records the selected button and passes the
        change value back to variable.
        '''
        super(PlotDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.data = data
        self.ydata = ydata
        self.plot_type = plot_type

        # Set plot title and colorbar units to defaults
        self.title = title
        self.xlabel = xlabel
        self.ylabel = ylabel
        self.units = None
        self.limits = None

        # Find the PyArt colormap names
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Create the plot
        self._update_plot()
#        self.NewRadar(None, None, True)

        self.show()

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(4)

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add buttons along display for user control
        self.addButtons()
        self.setUILayout()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    ##################################
    # User display interface methods #
    ##################################
    def addButtons(self):
        '''Add a series of buttons for user control over display.'''
        # Create the Display controls
        self._add_displayBoxUI()

    def setUILayout(self):
        '''Setup the button/display UI layout.'''
        self.layout.addWidget(self.dispButton, 0, 1)

    #############################
    # Functionality methods #
    #############################

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(self.limits, self.cmap, self.name)
        if change == 1:
            self.cmap = cmap
            self.limits = limits
            self._update_plot()

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog(self.title, "Plot Title", "Title:")
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog(self.units, "Plot Units", "Units:")
        if entry is True:
            self.units = val
            self._update_plot()

    def _add_cmaps_to_button(self):
        '''Add a menu to change colormap used for plot.'''
        for cm_name in self.cm_names:
            cmapAction = self.dispCmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap" % cm_name)
            cmapAction.triggered[()].connect(
                lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
            self.dispCmap.setMenu(self.dispCmapmenu)

    def _add_displayBoxUI(self):
        '''Create the Display Options Button menu.'''
        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = dispmenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
        dispTitle = dispmenu.addAction("Change Title")
        dispTitle.setToolTip("Change plot title")
        dispUnit = dispmenu.addAction("Change Units")
        dispUnit.setToolTip("Change units string")
#        toolZoomPan = dispmenu.addAction("Zoom/Pan")
        self.dispCmap = dispmenu.addAction("Change Colormap")
        self.dispCmapmenu = QtGui.QMenu("Change Cmap")
        self.dispCmapmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        dispSaveFile = dispmenu.addAction("Save Image")
        dispSaveFile.setShortcut("Ctrl+S")
        dispSaveFile.setStatusTip("Save Image using dialog")
        self.dispHelp = dispmenu.addAction("Help")

        dispLimits.triggered[()].connect(self._open_LimsDialog)
        dispTitle.triggered[()].connect(self._title_input)
        dispUnit.triggered[()].connect(self._units_input)
#        toolZoomPan.triggered[()].connect(self.toolZoomPanCmd)
        dispSaveFile.triggered[()].connect(self._savefile)
        self.dispHelp.triggered[()].connect(self.displayHelp)

        self._add_cmaps_to_button()
        self.dispButton.setMenu(dispmenu)

    def displayHelp(self):
        text = (
            "<b>Using the Simple Plot Feature</b><br><br>"
            "<i>Purpose</i>:<br>"
            "Display a plot.<br><br>"
            "The limits dialog is a common format that allows the user "
            "change:<br>"
            "<i>X and Y limits<br>"
            "Data limits</i><br>"
            "However, not all plots take each argument.<br>"
            "For example, a simple line plot has no data min/max data "
            "value.<br>")

        common.ShowLongText(text)

    ########################
    # Selectionion methods #
    ########################

#     def _create_plot(self):
#         '''
#         Create a plot
#         '''
#         # test for None
#         if self.Vradar.value is None:
#             self.fieldBox.clear()
#             self.tiltBox.clear()
#             return
#
#         # Get the tilt angles
#         self.rTilts = self.Vradar.value.sweep_number['data'][:]
#         # Get field names
#         self.fieldnames = self.Vradar.value.fields.keys()
#
#         # Check the file type and initialize limts
#         self._check_file_type()
#
#         # Update field and tilt MenuBox
#         self._fillTiltBox()
#         self._fillFieldBox()
#
#         self.units = None
#         if strong:
#             self._update_plot()

#     def NewLims(self, variable, value, strong):
#         '''
#         Slot for 'ValueChanged' signal of
#         :py:class:`Vlims <artview.core.core.Variable>`.
#
#         This will:
#
#         * If strong update: update axes
#         '''
#         if strong:
#             self._update_axes()

#     def NewCmap(self, variable, value, strong):
#         '''
#         Slot for 'ValueChanged' signal of
#         :py:class:`Vcmap <artview.core.core.Variable>`.
#
#         This will:
#
#         * If strong update: update plot
#         '''
#         if strong and self.Vradar.value is not None:
#             self._update_plot()

    def cmapSelectCmd(self, cm_name):
        '''Captures colormap selection and redraws.'''
        self.cmap['cmap'] = cm_name
#        self.Vcmap.value['cmap'] = cm_name
#        self.Vcmap.update()

#    def toolZoomPanCmd(self):
#        '''Creates and connects to a Zoom/Pan instance.'''
#        from .tools import ZoomPan
#        scale = 1.1
#        self.tools['zoompan'] = ZoomPan(
#            self.limits, self.ax,
#            base_scale=scale, parent=self.parent)
#        self.tools['zoompan'].connect()

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 5
        self.YSIZE = 5
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])

#    def _update_fig_ax(self):
#        '''Set the figure and axis to plot.'''
#        if self.plot_type in ("radarAirborne", "radarRhi"):
#            self.YSIZE = 5
#        else:
#            self.YSIZE = 8
#        xwidth = 0.7
#        yheight = 0.7 * float(self.YSIZE) / float(self.XSIZE)
#        self.ax.set_position([0.2, 0.55-0.5*yheight, xwidth, yheight])
#        self.cax.set_position([0.2, 0.10, xwidth, 0.02])
#        self._update_axes()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 4, 3)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''

        # Create the plot with PyArt PlotDisplay
        self.ax.cla()  # Clear the plot axes

        # Reset to default title if user entered nothing w/ Title button
        if self.title == '':
            title = None
        else:
            title = self.title

        colorbar_flag = False

        self.cmap = {'vmin': self.data.min(), 'vmax': self.data.max(),
                     'cmap': 'pyart_RefDiff'}

        if self.plot_type == "hist":
            self.plot = self.ax.hist(
                self.data, bins=25,
                range=(self.cmap['vmin'], self.cmap['vmax']),
                figure=self.fig)
            self.ax.set_ylabel("Counts")
            if self.xlabel:
                self.ax.set_xlabel(self.xlabel)

        elif self.plot_type == "hist2d":
            # Check that y data was provided
            if self.ydata:
                y = self.ydata
            # Create Plot
            self.plot = self.ax.hist2d(
                self.data, y, bins=[25, 20],
                range=([self.cmap['vmin'], self.cmap['vmax']],
                       [y.min(), y.max()]),
                cmap=self.cm_name,
                figure=self.fig)
            colorbar_flag = True

        elif self.plot_type == "plot":
            # Check that y data was provided
            if self.ydata:
                y = self.ydata
            # Create Plot
            self.plot = self.ax.plot(self.data, y, figure=self.fig)

        # Set the axis labels if arguments passed
        if self.xlabel:
            self.ax.set_xlabel(self.xlabel)
        if self.ylabel:
            self.ax.set_ylabel(self.ylabel)

        # If limits exists, update the axes otherwise retrieve
        if self.limits:
            self._update_axes()
        else:
            self._get_axes_limits()

        # Set the title if passed
        if title is not None:
            self.ax.set_title(title)

        # If the colorbar flag is thrown, create it
        if colorbar_flag:
            # Clear the colorbar axes
            self.cax.cla()
            self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
            norm = mlabNormalize(vmin=self.cmap['vmin'],
                                 vmax=self.cmap['vmax'])
            self.cbar = mlabColorbarBase(self.cax, cmap=self.cm_name,
                                         norm=norm, orientation='horizontal')
            # colorbar - use specified units or default depending on
            # what has or has not been entered
            if self.units is None or self.units == '':
                self.units = ''
            self.cbar.set_label(self.units)

        self.canvas.draw()

    def _update_axes(self):
        '''Change the Plot Axes.'''
        self.ax.set_xlim(self.limits['xmin'], self.limits['xmax'])
        self.ax.set_ylim(self.limits['ymin'], self.limits['ymax'])
        self.ax.figure.canvas.draw()

    def _get_axes_limits(self):
        '''Get the axes limits'''
        xlim = self.ax.get_xlim()
        ylim = self.ax.get_ylim()
        self.limits = {}
        self.limits['xmin'] = xlim[0]
        self.limits['xmax'] = xlim[1]
        self.limits['ymin'] = ylim[0]
        self.limits['ymax'] = ylim[1]

    ########################
    # Image save methods #
    ########################

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', ' ', file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)
예제 #49
0
class MplFigureCellWidget(QCellWidget):
    """
    MplFigureCellWidget is the actual QWidget taking the FigureManager
    as a child for displaying figures

    """
    save_formats = ["Portable Document Format (*.pdf)",
                    "Portable Network Graphic (*.png)",
                    "PostScript (*.ps *.eps)",
                    "Raw images (*.raw *.rgba)",
                    "Scalable Vector Graphics (*.svg *.svgz)"]

    def __init__(self, parent=None):
        """ MplFigureCellWidget(parent: QWidget) -> MplFigureCellWidget
        Initialize the widget with its central layout
        
        """
        QCellWidget.__init__(self, parent)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        centralLayout = QtGui.QVBoxLayout()
        self.setLayout(centralLayout)
        centralLayout.setMargin(0)
        centralLayout.setSpacing(0)
        self.canvas = None
        self.figure = None
        self.figManager = None
        self.toolBarType = MplFigureCellToolBar
        self.mplToolbar = None

    def updateContents(self, inputPorts):
        """ updateContents(inputPorts: tuple) -> None
        Update the widget contents based on the input data
        
        """
        (fig, ) = inputPorts
        if not self.figure or self.figure.number != fig.figInstance.number:
            if self.layout().count() > 0:
                self.layout().removeWidget(self.canvas)

            self.figure = fig.figInstance

            self.canvas = FigureCanvasQTAgg(self.figure)
            self.mplToolbar = MplNavigationToolbar(self.canvas, None)
            self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                      QtGui.QSizePolicy.Expanding)
            self.layout().addWidget(self.canvas)

    def keyPressEvent(self, event):
        print "KEY PRESS:",  event.key()
        self.canvas.keyPressEvent(event)

    def keyReleaseEvent(self, event):
        print "KEY RELEASE:", event.key()
        self.canvas.keyReleaseEvent(event)

    def deleteLater(self):
        """ deleteLater() -> None        
        Overriding PyQt deleteLater to free up resources
        
        """
        # Destroy the old one if possible
        if self.figure is not None:
            print "pylab:", pylab
            print "self.figure:", self.figure
            pylab.close(self.figure)

        QCellWidget.deleteLater(self)

    def grabWindowPixmap(self):
        """ grabWindowPixmap() -> QPixmap
        Widget special grabbing function
        
        """
        return QtGui.QPixmap.grabWidget(self.canvas)

    def dumpToFile(self, filename):
        previous_size = tuple(self.figure.get_size_inches())
        self.figure.set_size_inches(8.0,6.0)
        self.canvas.print_figure(filename)
        self.figure.set_size_inches(previous_size[0],previous_size[1])
        self.canvas.draw()
        
    def saveToPDF(self, filename):
        previous_size = tuple(self.figure.get_size_inches())
        self.figure.set_size_inches(8.0,6.0)
        self.canvas.print_figure(filename)
        self.figure.set_size_inches(previous_size[0],previous_size[1])
        self.canvas.draw()
예제 #50
0
class MplFigureCellWidget(QCellWidget):
    """
    MplFigureCellWidget is the actual QWidget taking the FigureManager
    as a child for displaying figures

    """
    save_formats = ["Portable Document Format (*.pdf)",
                    "Portable Network Graphic (*.png)",
                    "PostScript (*.ps *.eps)",
                    "Raw images (*.raw *.rgba)",
                    "Scalable Vector Graphics (*.svg *.svgz)"]

    def __init__(self, parent=None):
        """ MplFigureCellWidget(parent: QWidget) -> MplFigureCellWidget
        Initialize the widget with its central layout
        
        """
        QCellWidget.__init__(self, parent)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        centralLayout = QtGui.QVBoxLayout()
        self.setLayout(centralLayout)
        centralLayout.setMargin(0)
        centralLayout.setSpacing(0)
        self.canvas = None
        self.figure = None
        self.figManager = None
        self.toolBarType = MplFigureCellToolBar
        self.mplToolbar = None

    def updateContents(self, inputPorts):
        """ updateContents(inputPorts: tuple) -> None
        Update the widget contents based on the input data
        
        """
        (figInstance, ) = inputPorts
        if not self.figure or self.figure.number != figInstance.number:
            if self.layout().count() > 0:
                self.layout().removeWidget(self.canvas)

            self.figure = figInstance

            self.canvas = FigureCanvasQTAgg(self.figure)
            self.mplToolbar = MplNavigationToolbar(self.canvas, None)
            self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                      QtGui.QSizePolicy.Expanding)
            self.layout().addWidget(self.canvas)

    def keyPressEvent(self, event):
        self.canvas.keyPressEvent(event)

    def keyReleaseEvent(self, event):
        self.canvas.keyReleaseEvent(event)

    def deleteLater(self):
        """ deleteLater() -> None        
        Overriding PyQt deleteLater to free up resources
        
        """
        # Destroy the old one if possible
        if self.figure is not None:
            pylab.close(self.figure)

        QCellWidget.deleteLater(self)

    def grabWindowPixmap(self):
        """ grabWindowPixmap() -> QPixmap
        Widget special grabbing function
        
        """
        return QtGui.QPixmap.grabWidget(self.canvas)

    def dumpToFile(self, filename):
        previous_size = tuple(self.figure.get_size_inches())
        self.figure.set_size_inches(8.0,6.0)
        self.canvas.print_figure(filename)
        self.figure.set_size_inches(previous_size[0],previous_size[1])
        self.canvas.draw()
        
    def saveToPDF(self, filename):
        previous_size = tuple(self.figure.get_size_inches())
        self.figure.set_size_inches(8.0,6.0)
        self.canvas.print_figure(filename)
        self.figure.set_size_inches(previous_size[0],previous_size[1])
        self.canvas.draw()
예제 #51
0
class RadarDisplay(Component):
    '''
    Class to create a display plot, using a returned Radar structure
    from the PyArt pyart.graph package.
    '''

    Vradar = None  # : see :ref:`shared_variable`
    Vfield = None  # : see :ref:`shared_variable`
    Vtilt = None  # : see :ref:`shared_variable`
    Vlims = None  # : see :ref:`shared_variable`
    Vcmap = None  # : see :ref:`shared_variable`

    @classmethod
    def guiStart(self, parent=None):
        '''Graphical interface for starting this class'''
        args = _DisplayStart().startDisplay()
        return self(**args), True

    def __init__(self, Vradar, Vfield, Vtilt, Vlims=None, Vcmap=None,
                 name="RadarDisplay", parent=None):
        '''
        Initialize the class to create display.

        Parameters
        ----------
        Vradar : :py:class:`~artview.core.core.Variable` instance
            Radar signal variable.
        Vfield : :py:class:`~artview.core.core.Variable` instance
            Field signal variable.
        Vtilt : :py:class:`~artview.core.core.Variable` instance
            Tilt signal variable.
        [Optional]
        Vlims : :py:class:`~artview.core.core.Variable` instance
            Limits signal variable.
            A value of None will instantiate a limits variable.
        Vcmap : :py:class:`~artview.core.core.Variable` instance
            Colormap signal variable.
            A value of None will instantiate a colormap variable.
        name : string
            Display window name.
        parent : PyQt instance
            Parent instance to associate to Display window.
            If None, then Qt owns, otherwise associated with parent PyQt
            instance.

        Notes
        -----
        This class records the selected button and passes the
        change value back to variable.
        '''
        super(RadarDisplay, self).__init__(name=name, parent=parent)
        self.setFocusPolicy(QtCore.Qt.ClickFocus)
        # Set up signal, so that DISPLAY can react to
        # external (or internal) changes in radar, field,
        # lims and tilt (expected to be Core.Variable instances)
        # The capital V so people remember using ".value"
        self.Vradar = Vradar
        self.Vfield = Vfield
        self.Vtilt = Vtilt
        if Vlims is None:
            self.Vlims = Variable(None)
        else:
            self.Vlims = Vlims

        if Vcmap is None:
            self.Vcmap = Variable(None)
        else:
            self.Vcmap = Vcmap

        self.sharedVariables = {"Vradar": self.NewRadar,
                                "Vfield": self.NewField,
                                "Vtilt": self.NewTilt,
                                "Vlims": self.NewLims,
                                "Vcmap": self.NewCmap, }

        # Connect the components
        self.connectAllVariables()

        self.plot_type = None

        # Set plot title and colorbar units to defaults
        self.title = None
        self.units = None

        # Set the default range rings
        self.RngRingList = ["None", "10 km", "20 km", "30 km",
                            "50 km", "100 km"]
        self.RngRing = False

        # Find the PyArt colormap names
#        self.cm_names = [m for m in cm.datad if not m.endswith("_r")]
        self.cm_names = ["pyart_" + m for m in pyart.graph.cm.datad
                         if not m.endswith("_r")]
        self.cm_names.sort()

        # Create tool dictionary
        self.tools = {}

        # Set up Default limits and cmap
        if Vlims is None:
            self._set_default_limits(strong=False)
        if Vcmap is None:
            self._set_default_cmap(strong=False)

        # Create a figure for output
        self._set_fig_ax()

        # Launch the GUI interface
        self.LaunchGUI()

        # Initialize radar variable
        self.NewRadar(None, None, True)

        self.show()

    def keyPressEvent(self, event):
        '''Allow tilt adjustment via the Up-Down arrow keys.'''
        if event.key() == QtCore.Qt.Key_Up:
            self.TiltSelectCmd(self.Vtilt.value + 1)
        elif event.key() == QtCore.Qt.Key_Down:
            self.TiltSelectCmd(self.Vtilt.value - 1)
        else:
            super(RadarDisplay, self).keyPressEvent(event)

    ####################
    # GUI methods #
    ####################

    def LaunchGUI(self):
        '''Launches a GUI interface.'''
        # Create layout
        self.layout = QtGui.QGridLayout()
        self.layout.setSpacing(8)

        # Create the widget
        self.central_widget = QtGui.QWidget()
        self.setCentralWidget(self.central_widget)
        self._set_figure_canvas()

        self.central_widget.setLayout(self.layout)

        # Add buttons along display for user control
        self.addButtons()
        self.setUILayout()

        # Set the status bar to display messages
        self.statusbar = self.statusBar()

    ##################################
    # User display interface methods #
    ##################################
    def addButtons(self):
        '''Add a series of buttons for user control over display.'''
        # Create the Display controls
        self._add_displayBoxUI()
        # Create the Tilt controls
        self._add_tiltBoxUI()
        # Create the Field controls
        self._add_fieldBoxUI()
        # Create the Tools controls
        self._add_toolsBoxUI()
        # Create the Informational label at top
        self._add_infolabel()

    def setUILayout(self):
        '''Setup the button/display UI layout.'''
        self.layout.addWidget(self.tiltBox, 0, 0)
        self.layout.addWidget(self.fieldBox, 0, 1)
        self.layout.addWidget(self.dispButton, 0, 2)
        self.layout.addWidget(self.toolsButton, 0, 3)
        self.layout.addWidget(self.infolabel, 0, 4)

    #############################
    # Functionality methods #
    #############################

    def _open_LimsDialog(self):
        '''Open a dialog box to change display limits.'''
        from .limits import limits_dialog
        limits, cmap, change = limits_dialog(
            self.Vlims.value, self.Vcmap.value, self.name)
        if change == 1:
            self.Vcmap.change(cmap)
            self.Vlims.change(limits)

    def _fillTiltBox(self):
        '''Fill in the Tilt Window Box with current elevation angles.'''
        self.tiltBox.clear()
        self.tiltBox.addItem("Tilt Window")
        # Loop through and create each tilt button
        elevs = self.Vradar.value.fixed_angle['data'][:]
        for i, ntilt in enumerate(self.rTilts):
            btntxt = "%2.1f deg (Tilt %d)" % (elevs[i], i+1)
            self.tiltBox.addItem(btntxt)

    def _fillFieldBox(self):
        '''Fill in the Field Window Box with current variable names.'''
        self.fieldBox.clear()
        self.fieldBox.addItem("Field Window")
        # Loop through and create each field button
        for field in self.fieldnames:
            self.fieldBox.addItem(field)

    def _tiltAction(self, text):
        '''Define action for Tilt Button selection.'''
        if text == "Tilt Window":
            self._open_tiltbuttonwindow()
        else:
            ntilt = int(text.split("(Tilt ")[1][:-1])-1
            self.TiltSelectCmd(ntilt)

    def _fieldAction(self, text):
        '''Define action for Field Button selection.'''
        if text == "Field Window":
            self._open_fieldbuttonwindow()
        else:
            self.FieldSelectCmd(str(text))

    def _title_input(self):
        '''Retrieve new plot title.'''
        val, entry = common.string_dialog(self.title, "Plot Title", "Title:")
        if entry is True:
            self.title = val
            self._update_plot()

    def _units_input(self):
        '''Retrieve new plot units.'''
        val, entry = common.string_dialog(self.units, "Plot Units", "Units:")
        if entry is True:
            self.units = val
            self._update_plot()

    def _open_tiltbuttonwindow(self):
        '''Open a TiltButtonWindow instance.'''
        from .level import LevelButtonWindow
        self.tiltbuttonwindow = LevelButtonWindow(
            self.Vtilt, plot_type=self.plot_type, Vcontainer=self.Vradar,
            name=self.name+" Tilt Selection", parent=self.parent)

    def _open_fieldbuttonwindow(self):
        '''Open a FieldButtonWindow instance.'''
        from .field import FieldButtonWindow
        self.fieldbuttonwindow = FieldButtonWindow(
            self.Vradar, self.Vfield,
            name=self.name+" Field Selection", parent=self.parent)

    def _add_RngRing_to_button(self):
        '''Add a menu to display range rings on plot.'''
        for RngRing in self.RngRingList:
            RingAction = self.dispRngRingmenu.addAction(RngRing)
            RingAction.setStatusTip("Apply Range Rings every %s" % RngRing)
            RingAction.triggered[()].connect(
                lambda RngRing=RngRing: self.RngRingSelectCmd(RngRing))
            self.dispRngRing.setMenu(self.dispRngRingmenu)

    def _add_cmaps_to_button(self):
        '''Add a menu to change colormap used for plot.'''
        for cm_name in self.cm_names:
            cmapAction = self.dispCmapmenu.addAction(cm_name)
            cmapAction.setStatusTip("Use the %s colormap" % cm_name)
            cmapAction.triggered[()].connect(
                lambda cm_name=cm_name: self.cmapSelectCmd(cm_name))
            self.dispCmap.setMenu(self.dispCmapmenu)

    def _add_displayBoxUI(self):
        '''Create the Display Options Button menu.'''
        self.dispButton = QtGui.QPushButton("Display Options")
        self.dispButton.setToolTip("Adjust display properties")
        self.dispButton.setFocusPolicy(QtCore.Qt.NoFocus)
        dispmenu = QtGui.QMenu(self)
        dispLimits = dispmenu.addAction("Adjust Display Limits")
        dispLimits.setToolTip("Set data, X, and Y range limits")
        dispTitle = dispmenu.addAction("Change Title")
        dispTitle.setToolTip("Change plot title")
        dispUnit = dispmenu.addAction("Change Units")
        dispUnit.setToolTip("Change units string")
        self.dispRngRing = dispmenu.addAction("Add Range Rings")
        self.dispRngRingmenu = QtGui.QMenu("Add Range Rings")
        self.dispRngRingmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        self.dispCmap = dispmenu.addAction("Change Colormap")
        self.dispCmapmenu = QtGui.QMenu("Change Cmap")
        self.dispCmapmenu.setFocusPolicy(QtCore.Qt.NoFocus)
        dispQuickSave = dispmenu.addAction("Quick Save Image")
        dispQuickSave.setShortcut("Ctrl+D")
        dispQuickSave.setToolTip(
            "Save Image to local directory with default name")
        dispSaveFile = dispmenu.addAction("Save Image")
        dispSaveFile.setShortcut("Ctrl+S")
        dispSaveFile.setStatusTip("Save Image using dialog")

        dispLimits.triggered[()].connect(self._open_LimsDialog)
        dispTitle.triggered[()].connect(self._title_input)
        dispUnit.triggered[()].connect(self._units_input)
        dispQuickSave.triggered[()].connect(self._quick_savefile)
        dispSaveFile.triggered[()].connect(self._savefile)

        self._add_RngRing_to_button()
        self._add_cmaps_to_button()
        self.dispButton.setMenu(dispmenu)

    def _add_tiltBoxUI(self):
        '''Create the Tilt Selection ComboBox.'''
        self.tiltBox = QtGui.QComboBox()
        self.tiltBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.tiltBox.setToolTip("Select tilt elevation angle to display.\n"
                                "'Tilt Window' will launch popup.\n"
                                "Up/Down arrow keys Increase/Decrease tilt.")
        self.tiltBox.activated[str].connect(self._tiltAction)

    def _add_fieldBoxUI(self):
        '''Create the Field Selection ComboBox.'''
        self.fieldBox = QtGui.QComboBox()
        self.fieldBox.setFocusPolicy(QtCore.Qt.NoFocus)
        self.fieldBox.setToolTip("Select variable/field in data file.\n"
                                 "'Field Window' will launch popup.\n")
        self.fieldBox.activated[str].connect(self._fieldAction)

    def _add_toolsBoxUI(self):
        '''Create the Tools Button menu.'''
        self.toolsButton = QtGui.QPushButton("Toolbox")
        self.toolsButton.setFocusPolicy(QtCore.Qt.NoFocus)
        self.toolsButton.setToolTip("Choose a tool to apply")
        toolmenu = QtGui.QMenu(self)
        toolZoomPan = toolmenu.addAction("Zoom/Pan")
        toolValueClick = toolmenu.addAction("Click for Value")
        toolSelectRegion = toolmenu.addAction("Select a Region of Interest")
        toolCustom = toolmenu.addAction("Use Custom Tool")
        toolReset = toolmenu.addAction("Reset Tools")
        toolDefault = toolmenu.addAction("Reset File Defaults")
        toolZoomPan.triggered[()].connect(self.toolZoomPanCmd)
        toolValueClick.triggered[()].connect(self.toolValueClickCmd)
        toolSelectRegion.triggered[()].connect(self.toolSelectRegionCmd)
        toolCustom.triggered[()].connect(self.toolCustomCmd)
        toolReset.triggered[()].connect(self.toolResetCmd)
        toolDefault.triggered[()].connect(self.toolDefaultCmd)
        self.toolsButton.setMenu(toolmenu)

    def _add_infolabel(self):
        '''Create an information label about the display'''
        self.infolabel = QtGui.QLabel("Radar: \n"
                                      "Field: \n"
                                      "Tilt: ", self)
        self.infolabel.setStyleSheet('color: red; font: italic 10px')
        self.infolabel.setToolTip("Filename not loaded")

    def _update_infolabel(self):
        self.infolabel.setText("Radar: %s\n"
                               "Field: %s\n"
                               "Tilt: %d" % (
                                   self.Vradar.value.metadata[
                                       'instrument_name'],
                                   self.Vfield.value,
                                   self.Vtilt.value+1))
        if hasattr(self.Vradar.value, 'filename'):
            self.infolabel.setToolTip(self.Vradar.value.filename)

    ########################
    # Selectionion methods #
    ########################

    def NewRadar(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vradar <artview.core.core.Variable>`.

        This will:

        * Update fields and tilts lists and MenuBoxes
        * Check radar scan type and reset limits if needed
        * Reset units and title
        * If strong update: update plot
        '''
        # test for None
        if self.Vradar.value is None:
            self.fieldBox.clear()
            self.tiltBox.clear()
            return

        # Get the tilt angles
        self.rTilts = self.Vradar.value.sweep_number['data'][:]
        # Get field names
        self.fieldnames = self.Vradar.value.fields.keys()

        # Check the file type and initialize limts
        self._check_file_type()

        # Update field and tilt MenuBox
        self._fillTiltBox()
        self._fillFieldBox()

        self.units = None
        self.title = None
        if strong:
            self._update_plot()
            self._update_infolabel()

    def NewField(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vfield <artview.core.core.Variable>`.

        This will:

        * Reset colormap
        * Reset units
        * Update fields MenuBox
        * If strong update: update plot
        '''
        self._set_default_cmap(strong=False)
        self.units = None
        idx = self.fieldBox.findText(value)
        self.fieldBox.setCurrentIndex(idx)
        if strong and self.Vradar.value is not None:
            self._update_plot()
            self._update_infolabel()

    def NewLims(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vlims <artview.core.core.Variable>`.

        This will:

        * If strong update: update axes
        '''
        if strong:
            self._update_axes()

    def NewCmap(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vcmap <artview.core.core.Variable>`.

        This will:

        * If strong update: update plot
        '''
        if strong and self.Vradar.value is not None:
            self._update_plot()

    def NewTilt(self, variable, value, strong):
        '''
        Slot for 'ValueChanged' signal of
        :py:class:`Vtilt <artview.core.core.Variable>`.

        This will:

        * Update tilt MenuBox
        * If strong update: update plot
        '''
        # +1 since the first one is "Tilt Window"
        self.tiltBox.setCurrentIndex(value+1)
        if strong and self.Vradar.value is not None:
            self._update_plot()
            self._update_infolabel()

    def TiltSelectCmd(self, ntilt):
        '''
        Captures tilt selection and update tilt
        :py:class:`~artview.core.core.Variable`.
        '''
        if ntilt < 0:
            ntilt = len(self.rTilts)-1
        elif ntilt >= len(self.rTilts):
            ntilt = 0
        self.Vtilt.change(ntilt)

    def FieldSelectCmd(self, name):
        '''
        Captures field selection and update field
        :py:class:`~artview.core.core.Variable`.
        '''
        self.Vfield.change(name)

    def RngRingSelectCmd(self, ringSel):
        '''
        Captures Range Ring selection and
        redraws the field with range rings.
        '''
        if ringSel is "None":
            self.RngRing = False
        else:
            self.RngRing = True
            # Find the unambigous range of the radar
            try:
                unrng = int(self.Vradar.value.instrument_parameters[
                    'unambiguous_range']['data'][0]/1000)
            except:
                unrng = int(self.Vlims.value['xmax'])

            # Set the step
            if ringSel == '10 km':
                ringdel = 10
            if ringSel == '20 km':
                ringdel = 20
            if ringSel == '30 km':
                ringdel = 30
            if ringSel == '50 km':
                ringdel = 50
            if ringSel == '100 km':
                ringdel = 100

            # Calculate an array of range rings
            self.RNG_RINGS = range(ringdel, unrng, ringdel)

        if self.Vradar.value is not None:
            self._update_plot()

    def cmapSelectCmd(self, cm_name):
        '''Captures colormap selection and redraws.'''
        CMAP = cm_name
        self.Vcmap.value['cmap'] = cm_name
        self.Vcmap.change(self.Vcmap.value)

    def toolZoomPanCmd(self):
        '''Creates and connects to a Zoom/Pan instance.'''
        from .tools import ZoomPan
        scale = 1.1
        self.tools['zoompan'] = ZoomPan(
            self.Vlims, self.ax,
            base_scale=scale, parent=self.parent)
        self.tools['zoompan'].connect()

    def toolValueClickCmd(self):
        '''Creates and connects to Point-and-click value retrieval'''
        from .tools import ValueClick
        self.tools['valueclick'] = ValueClick(
            self.Vradar, self.Vtilt, self.Vfield,
            self.units, self.ax, self.statusbar, parent=self.parent)
        self.tools['valueclick'].connect()

    def toolSelectRegionCmd(self):
        '''Creates and connects to Region of Interest instance'''
        from .select_region import SelectRegion
        self.tools['select_region'] = SelectRegion(
            self, name=self.name + " SelectRegion", parent=self)

    def toolCustomCmd(self):
        '''Allow user to activate self-defined tool.'''
        from . import tools
        tools.custom_tool(self.tools)

    def toolResetCmd(self):
        '''Reset tools via disconnect.'''
        from . import tools
        self.tools = tools.reset_tools(self.tools)

    def toolDefaultCmd(self):
        '''Restore the Display defaults.'''
        from . import tools
        self.tools, limits, cmap = tools.restore_default_display(
            self.tools, self.Vfield.value, self.plot_type)
        self.Vcmap.change(cmap)
        self.Vlims.change(limits)

    def getPathInteriorValues(self, path):
        '''
        Return the bins values path.

        Parameters
        ----------
        path : Matplotlib Path instance

        Returns
        -------
        x, y, azi, range, value, ray_idx, range_inx: ndarray
            Truplet of 1arrays containing x,y coordinate, azimuth,
            range, current field value, ray index and range index
            for all bin of the current radar and tilt inside path.

        Notes
        -----
            If Vradar.value is None, returns None
        '''
        from .tools import interior_radar
        radar = self.Vradar.value
        if radar is None:
            return (np.array([]),)*7

        xy, idx = interior_radar(path, radar, self.Vtilt.value)
        aux = (xy[:, 0], xy[:, 1], radar.azimuth['data'][idx[:, 0]],
               radar.range['data'][idx[:, 1]] / 1000.,
               radar.fields[self.Vfield.value]['data'][idx[:, 0], idx[:, 1]],
               idx[:, 0], idx[:, 1])
        return aux

    ####################
    # Plotting methods #
    ####################

    def _set_fig_ax(self):
        '''Set the figure and axis to plot.'''
        self.XSIZE = 8
        self.YSIZE = 8
        self.fig = Figure(figsize=(self.XSIZE, self.YSIZE))
        self.ax = self.fig.add_axes([0.2, 0.2, 0.7, 0.7])
        self.cax = self.fig.add_axes([0.2, 0.10, 0.7, 0.02])
        # self._update_axes()

    def _update_fig_ax(self):
        '''Set the figure and axis to plot.'''
        if self.plot_type in ("radarAirborne", "radarRhi"):
            self.YSIZE = 5
        else:
            self.YSIZE = 8
        xwidth = 0.7
        yheight = 0.7  # * float(self.YSIZE) / float(self.XSIZE)
        self.ax.set_position([0.2, 0.55-0.5*yheight, xwidth, yheight])
        self.cax.set_position([0.2, 0.10, xwidth, 0.02])
        self._update_axes()

    def _set_figure_canvas(self):
        '''Set the figure canvas to draw in window area.'''
        self.canvas = FigureCanvasQTAgg(self.fig)
        # Add the widget to the canvas
        self.layout.addWidget(self.canvas, 1, 0, 7, 6)

    def _update_plot(self):
        '''Draw/Redraw the plot.'''

        # Create the plot with PyArt RadarDisplay
        self.ax.cla()  # Clear the plot axes
        self.cax.cla()  # Clear the colorbar axes

        if self.Vfield.value not in self.Vradar.value.fields.keys():
            self.canvas.draw()
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(255,0,0,255);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.showMessage("Field not Found in Radar", msecs=5000)
            return
        else:
            self.statusbar.setStyleSheet("QStatusBar{padding-left:8px;" +
                                         "background:rgba(0,0,0,0);" +
                                         "color:black;font-weight:bold;}")
            self.statusbar.clearMessage()

        # Reset to default title if user entered nothing w/ Title button
        if self.title == '':
            title = None
        else:
            title = self.title

        limits = self.Vlims.value
        cmap = self.Vcmap.value

        if self.plot_type == "radarAirborne":
            self.display = pyart.graph.RadarDisplay_Airborne(self.Vradar.value)

            self.plot = self.display.plot_sweep_grid(
                self.Vfield.value, vmin=cmap['vmin'],
                vmax=cmap['vmax'], colorbar_flag=False, cmap=cmap['cmap'],
                ax=self.ax, fig=self.fig, title=title)
            self.display.plot_grid_lines()

        elif self.plot_type == "radarPpi":
            self.display = pyart.graph.RadarDisplay(self.Vradar.value)
            # Create Plot
            self.plot = self.display.plot_ppi(
                self.Vfield.value, self.Vtilt.value,
                vmin=cmap['vmin'], vmax=cmap['vmax'],
                colorbar_flag=False, cmap=cmap['cmap'],
                ax=self.ax, fig=self.fig, title=self.title)
            # Add range rings
            if self.RngRing:
                self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)
            # Add radar location
            self.display.plot_cross_hair(5., ax=self.ax)

        elif self.plot_type == "radarRhi":
            self.display = pyart.graph.RadarDisplay(self.Vradar.value)
            # Create Plot
            self.plot = self.display.plot_rhi(
                self.Vfield.value, self.Vtilt.value,
                vmin=cmap['vmin'], vmax=cmap['vmax'],
                colorbar_flag=False, cmap=cmap['cmap'],
                ax=self.ax, fig=self.fig, title=self.title)
            # Add range rings
            if self.RngRing:
                self.display.plot_range_rings(self.RNG_RINGS, ax=self.ax)

        self._update_axes()
        norm = mlabNormalize(vmin=cmap['vmin'],
                             vmax=cmap['vmax'])
        self.cbar = mlabColorbarBase(self.cax, cmap=cmap['cmap'],
                                     norm=norm, orientation='horizontal')
        # colorbar - use specified units or default depending on
        # what has or has not been entered
        if self.units is None or self.units == '':
            try:
                self.units = self.Vradar.value.fields[self.field]['units']
            except:
                self.units = ''
        self.cbar.set_label(self.units)

#        print "Plotting %s field, Tilt %d in %s" % (
#            self.Vfield.value, self.Vtilt.value+1, self.name)
        self.canvas.draw()

    def _update_axes(self):
        '''Change the Plot Axes.'''
        limits = self.Vlims.value
        self.ax.set_xlim(limits['xmin'], limits['xmax'])
        self.ax.set_ylim(limits['ymin'], limits['ymax'])
        self.ax.figure.canvas.draw()

    #########################
    # Check methods #
    #########################

    def _check_file_type(self):
        '''Check file to see if the file is airborne or rhi.'''
        radar = self.Vradar.value
        old_plot_type = self.plot_type
        if radar.scan_type != 'rhi':
            self.plot_type = "radarPpi"
        else:
            if 'platform_type' in radar.metadata:
                if (radar.metadata['platform_type'] == 'aircraft_tail' or
                        radar.metadata['platform_type'] == 'aircraft'):
                    self.plot_type = "radarAirborne"
                else:
                    self.plot_type = "radarRhi"
            else:
                self.plot_type = "radarRhi"

        if self.plot_type != old_plot_type:
            print("Changed Scan types, reinitializing")
            self._set_default_limits()
            self._update_fig_ax()

    def _set_default_limits(self, strong=True):
        ''' Set limits to pre-defined default.'''
        from .limits import _default_limits
        limits, cmap = _default_limits(
            self.Vfield.value, self.plot_type)
        self.Vlims.change(limits, strong)

    def _set_default_cmap(self, strong=True):
        ''' Set colormap to pre-defined default.'''
        from .limits import _default_limits
        limits, cmap = _default_limits(
            self.Vfield.value, self.plot_type)
        self.Vcmap.change(cmap, strong)

    ########################
    # Image save methods #
    ########################
    def _quick_savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display via PyArt interface.'''
        imagename = self.display.generate_filename(
            self.Vfield.value, self.Vtilt.value, ext=IMAGE_EXT)
        self.canvas.print_figure(os.path.join(os.getcwd(), imagename), dpi=DPI)
        self.statusbar.showMessage(
            'Saved to %s' % os.path.join(os.getcwd(), imagename))

    def _savefile(self, PTYPE=IMAGE_EXT):
        '''Save the current display using PyQt dialog interface.'''
        PBNAME = self.display.generate_filename(
            self.Vfield.value, self.Vtilt.value, ext=IMAGE_EXT)
        file_choices = "PNG (*.png)|*.png"
        path = unicode(QtGui.QFileDialog.getSaveFileName(
            self, 'Save file', PBNAME, file_choices))
        if path:
            self.canvas.print_figure(path, dpi=DPI)
            self.statusbar.showMessage('Saved to %s' % path)

    ########################
    #      get methods     #
    ########################

    def getPlotAxis(self):
        ''' get :py:class:`matplotlib.axes.Axes` instance of main plot '''
        return self.ax

    def getStatusBar(self):
        ''' get :py:class:`PyQt4.QtGui.QStatusBar` instance'''
        return self.statusbar

    def getField(self):
        ''' get current field '''
        return self.Vfield.value

    def getUnits(self):
        ''' get current units '''
        return self.units
예제 #52
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setWindowTitle("PyQt & matplotlib Test")

        self.createActions()
        self.createMenus()
        self.createMainFrame()
        self.createStatusBar()

        self.onDraw()

    def createActions(self):
        self.saveFileAction=QAction("&Save Plot", self, shortcut="Ctrl+S", triggered=self.savePlot, toolTip="Save the plot")
        self.quitAction=QAction("&Quit", self, shortcut="Ctrl+Q", triggered=self.close, toolTip="Close the application")
        self.aboutAction=QAction("&About", self, shortcut="F1", triggered=self.onAbout, toolTip="About this test")

    def createMenus(self):
        self.fileMenu=self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.saveFileAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAction)

        self.helpMenu=self.menuBar().addMenu("&Help")
        self.helpMenu.addAction(self.aboutAction)

    def createMainFrame(self):
        mainWidget=QWidget(self)
        QVBoxLayout(mainWidget)

        # matplotlib widget setup
        self.figure=Figure((5.0, 4.0), dpi=100)
        self.canvas=FigureCanvas(self.figure)
        self.canvas.setParent(mainWidget)
        mainWidget.layout().addWidget(self.canvas)

        self.axes=self.figure.add_subplot(111)

        self.canvas.mpl_connect('pick_event', self.onPick)
        self.canvas.mpl_connect('motion_notify_event', self.onMove)

        self.mplToolbar=NavToolbar(self.canvas, mainWidget)
        mainWidget.layout().addWidget(self.mplToolbar)

        # other widget setup
        controlLayout=QHBoxLayout()        

        self.textbox=QLineEdit('1 2 3 4', editingFinished=self.onDraw, minimumWidth=200)
        controlLayout.addWidget(self.textbox, Qt.AlignVCenter)

        drawButton=QPushButton('&Draw', clicked=self.onDraw)
        controlLayout.addWidget(drawButton, Qt.AlignVCenter)

        self.showGrid=QCheckBox("Show &Grid", checked=False, stateChanged=self.onDraw)
        controlLayout.addWidget(self.showGrid, Qt.AlignVCenter)

        controlLayout.addWidget(QLabel("Bar Width (%)"), Qt.AlignVCenter)

        self.slider=QSlider(Qt.Horizontal, minimum=1, maximum=100, value=20, tracking=True, tickPosition=QSlider.TicksBothSides, valueChanged=self.onDraw)
        controlLayout.addWidget(self.slider, Qt.AlignVCenter)

        mainWidget.layout().addLayout(controlLayout)

        # test layout 1
        testLayout1=QHBoxLayout()

        testLayout1.addWidget(QLabel("x:", self))
        self.xValue=QLineEdit("0", self)
        testLayout1.addWidget(self.xValue)

        testLayout1.addWidget(QLabel("y:", self))
        self.yValue=QLineEdit("0", self)
        testLayout1.addWidget(self.yValue)

        testLayout1.addWidget(QLabel("pixels"))

        mainWidget.layout().addLayout(testLayout1)

        self.setCentralWidget(mainWidget)

        # test layout 2
        testLayout2=QHBoxLayout()

        testLayout2.addWidget(QLabel("x:", self))
        self.xdValue=QLineEdit("0", self)
        testLayout2.addWidget(self.xdValue)

        testLayout2.addWidget(QLabel("y:", self))
        self.ydValue=QLineEdit("0", self)
        testLayout2.addWidget(self.ydValue)

        testLayout2.addWidget(QLabel("data"))

        mainWidget.layout().addLayout(testLayout2)

    def createStatusBar(self):
        self.statusBar().addWidget(QLabel("This is a test"), 1)

    @pyqtSlot()
    def savePlot(self):
        path=str(QFileDialog.getSaveFileName(self, 'Save Plot...', '', FILE_FORMATS_STR))
        print "Save Path:", path
        if path: self.canvas.print_figure(path)

    @pyqtSlot()
    def onAbout(self):
        QMessageBox.about(
            self,
            "About this test",
            """
            <p>A test of using PyQt with matplotlib:</p>    
            <ul>
                <li>Use the matplotlib navigation bar</li>
                <li>Add values to the text box and press Enter (or click "Draw")</li>
                <li>Show or hide the grid</li>
                <li>Drag the slider to modify the width of the bars</li>
                <li>Save the plot to a file using the File menu</li>
                <li>Click on a bar to receive an informative message</li>
            </ul>
            """)

    def onPick(self, event):
        QMessageBox.information(
            self,
            "Click!",
            "You've clicked on a bar with coords:\n%s" % event.artist.get_bbox().get_points())

    def onMove(self, event):
        self.xValue.setText("%d" % event.x)
        self.yValue.setText("%d" % event.y)

        if event.inaxes:
            self.xdValue.setText("%f" % event.xdata)
            self.ydValue.setText("%f" % event.ydata)

    @pyqtSlot()
    def onDraw(self):
        data=map(int, str(self.textbox.text()).split())
        x=range(len(data))

        e=0.5*(randn(len(data)))

        self.axes.clear()
        self.axes.grid(self.showGrid.isChecked())
        self.axes.bar(
            left=x,
            height=data,
            width=self.slider.value()/100.0,
            align='center',
            picker=5,
            alpha=0.5)

        self.axes.errorbar(x, data, e, fmt='o', ms=0)

        self.canvas.draw()