class MplCanvas(FigureCanvasQTAgg, customthreads.StoppableThread):

    def __init__(self, parent=None, width=5, height=4, channel=1,
                 dpi=100, *args, **kwargs):

        customthreads.StoppableThread.__init__(self, *args, **kwargs)
        self.in_queue = queue.Queue()

        self.fig = Figure(figsize=(width, height), dpi=dpi)
        FigureCanvasQTAgg.__init__(self, self.fig)
        FigureCanvasQTAgg.setSizePolicy(self,
                                        QtWidgets.QSizePolicy.Expanding,
                                        QtWidgets.QSizePolicy.Expanding)
        FigureCanvasQTAgg.updateGeometry(self)

        self.axes_list = []
        self.ylim = None

        self.setParent(parent)
        self.set_channel(channel)

        # self.axes = self.fig.add_subplot(111)
        # self.axes.hold(False)

    def set_channel(self, channel):
        self.channel = channel

        '''clear subplots'''
        if(self.axes_list is not []):
            for ax in self.axes_list:
                self.fig.delaxes(ax)
        self.axes_list = []

        for i in range(1, self.channel+1):
            self.axes_list.append(self.fig.add_subplot(self.channel, 1, i))
        for ax in self.axes_list:
            ax.hold(False)

    def set_lim(self, dtype):
        self.typeinfo = numpy.iinfo(dtype)
        self.ylim = [self.typeinfo.min, self.typeinfo.max]

    def split_channel(self, data):
        return numpy.transpose(numpy.reshape(data, (len(data)/self.channel, self.channel)))

    def run(self):
        '''Thread Loop'''
        while(self.is_stopped() is False):
            try:
                data = self.in_queue.get_nowait()
                split_data = self.split_channel(data)
                for i in range(self.channel):
                    # print(split_data[i], len(split_data[i]))
                    self.axes_list[i].plot(range(len(split_data[i])), split_data[i], 'b')
                    self.axes_list[i].set_ylim(self.ylim)
                self.draw()

            except queue.Empty:
                '''do nothing'''
                pass
class QTwostageModelWindow(QTclPopupWindow):
    def __init__(self, parent, title, twostage_inp, is_modal=False):
        self.dresult = "NONE"
        self.durvar = self.getvar(twostage_inp.duration)
        self.cNTvar = self.getvar(twostage_inp.cNT)
        self.caggvar = self.getvar(twostage_inp.cagg)
        self.rNTvar = self.getvar(twostage_inp.rNT)
        self.raggvar = self.getvar(twostage_inp.ragg)
        super().__init__(parent, title, is_modal)

    def loaded(self):
        pass

    def make_gui(self, title):
        self.setwintitle(title)

        row = 0
        setfr = self.make_label_frame(lrow=row,
                                      caption='Enter data for core and rim',
                                      padx=(5, 2),
                                      pady=(5, 5))

        irow = 0
        self.makelabel(setfr, lrow=irow, lcol=1, caption='core', sticky=tk.EW)
        self.makelabel(setfr, lrow=irow, lcol=2, caption='rim', sticky=tk.EW)

        irow += 1
        self.cNT, self.rNT = self.make_double_entrypair(setfr,
                                                        lrow=irow,
                                                        e1row=irow,
                                                        e2row=irow,
                                                        caption='[NT]: ',
                                                        var1=self.cNTvar,
                                                        var2=self.rNTvar,
                                                        padx=(5, 5),
                                                        pady=(5, 2))
        self.makelabel(setfr, lrow=irow, lcol=3, caption='(ppm)', sticky=tk.W)

        irow += 1
        self.cNT, self.rNT = self.make_double_entrypair(setfr,
                                                        lrow=irow,
                                                        e1row=irow,
                                                        e2row=irow,
                                                        caption='[NB]/[NT]: ',
                                                        var1=self.caggvar,
                                                        var2=self.raggvar,
                                                        padx=(5, 5),
                                                        pady=(2, 2))
        self.makelabel(setfr, lrow=irow, lcol=3, caption='(-)', sticky=tk.W)

        irow += 1
        self.make_double_entry(setfr,
                               lrow=irow,
                               erow=irow,
                               caption='Total duration: ',
                               textvariable=self.durvar,
                               padx=(2, 2),
                               pady=(2, 5))
        self.makelabel(setfr, lrow=irow, lcol=2, caption='(Ma)', sticky=tk.W)

        irow += 1
        self.makebutton(setfr,
                        erow=irow,
                        ecol=1,
                        cmd=self.calc_model,
                        caption='Calculate')
        self.savebutton = self.makebutton(setfr,
                                          erow=irow,
                                          ecol=2,
                                          cmd=self.save_to_file,
                                          caption='Save results to file')
        self.savebutton.config(state=tk.DISABLED)

        plotfr = self.make_label_frame(lrow=row,
                                       lcol=2,
                                       caption='Model',
                                       pady=(5, 5))
        self.fig = Figure(dpi=100)
        jrow = 0
        self.canv = self.make_mplcanvas(plotfr, fig=self.fig, erow=jrow)

        jrow += 1
        toolbar_fr = self.make_frame(plotfr, erow=jrow)
        self.toolbar = NavigationToolbar2Tk(self.canv, toolbar_fr)

        row += 1
        self.add_std_buttons(row=row, dismisscol=0)

    def calc_model(self):
        for ax in self.fig.get_axes():
            self.fig.delaxes(ax)

        self.durations, self.temps1, self.temps2 = ts.model(
            self.durvar.get(), self.cNTvar.get(), self.caggvar.get(),
            self.rNTvar.get(), self.raggvar.get())
        sp = self.fig.add_subplot(111)
        sp.plot(self.durations, self.temps1, 'r.', label='core')
        sp.plot(self.durations, self.temps2, 'b.', label='rim')
        sp.set(ylim=(1000, 1500),
               xlim=(0, float(self.durvar.get())),
               xlabel='Duration of first anneal (Ma)',
               ylabel='Temperature ($\mathregular{^{\circ}}$C)')
        sp.legend(loc='best')

        self.canv.draw()
        self.savebutton.config(state=tk.NORMAL)

    def save_to_file(self):
        fname = fd.asksaveasfilename(title='Save results to...',
                                     initialdir=QSettings.userhome,
                                     defaultextension='.csv')
        if fname != '':
            data = np.column_stack((self.durations, self.temps1, self.temps2))

            header = 'two-stage model with {} Ma; core: NT {} agg {}; rim: NT {} ragg {}\nduration of first anneal, T_core, T_rim'.format(
                self.durvar.get(), self.cNTvar.get(), self.caggvar.get(),
                self.rNTvar.get(), self.raggvar.get())
            np.savetxt(fname, data, delimiter=',', header=header)
        else:
            raise NameError('No file created, results not saved.')
Exemple #3
0
class MainWindow(QtGui.QMainWindow):
	def __init__(self, parent=None):
		super(MainWindow, self).__init__(parent)
		self.musics = None
		self.t_end = 0
		self.dat_idx = None
		self.selected_clusters = None
		self.mainLayout = QtGui.QHBoxLayout()

		self.open_folder_button = QtGui.QPushButton('open folder')
		self.open_folder_button.setFixedWidth(100)
		self.connect(self.open_folder_button, QtCore.SIGNAL('clicked()'), self.open_folder)
	
		self.statusBar().showMessage('Welcome')

		self.num_of_clusters = QtGui.QLineEdit()
		self.num_of_clusters.setFixedWidth(20)
		self.num_of_clusters.setText('12')
		self.num_of_clusters.setAlignment(QtCore.Qt.AlignLeft)

		self.mode_select = QtGui.QButtonGroup()
		lyrics = QtGui.QRadioButton('only lyrics')
		chords = QtGui.QRadioButton('only chords')
		both = QtGui.QRadioButton('both')
		both.setChecked(True)
		self.mode_select.addButton(lyrics, 0)
		self.mode_select.addButton(chords, 1)
		self.mode_select.addButton(both, 2)
	
		self.start_button = QtGui.QPushButton('start')
		self.start_button.setFixedWidth(100)
		self.connect(self.start_button, QtCore.SIGNAL('clicked()'), self.main)

		self.cluster_select = QtGui.QComboBox()
		self.cluster_select.setEditable(False)
		self.cluster_select.activated[str].connect(self.select_cluster)

		font = QtGui.QFont()
		font.setPointSize(12)
		self.results = QtGui.QTreeView()
		self.results.header().setFont(font)
		self.stdItemModel = QtGui.QStandardItemModel(0, 3)
		self.stdItemModel.setHeaderData(0, QtCore.Qt.Horizontal, 'Title')
		self.stdItemModel.setHeaderData(1, QtCore.Qt.Horizontal, 'Artist')
		self.stdItemModel.setHeaderData(2, QtCore.Qt.Horizontal, 'Original Key')
		self.results.setModel(self.stdItemModel)
		self.results.clicked.connect(self.plot_a_score)

		self.draw_frame = QtGui.QWidget()
		self.dpi = 100
		self.fig = Figure((5.0, 5.0), dpi=self.dpi)
		self.canvas = FigureCanvas(self.fig)
		self.canvas.setParent(self.draw_frame)
		self.axes = self.fig.add_axes([0.1, 0.1, 0.8, 0.8])
		
		self.mpl_toolbar = NavigationToolbar(self.canvas, self.draw_frame)

		leftLayout = QtGui.QVBoxLayout()
		label1 = QtGui.QLabel('properties')
		label1.setAlignment(QtCore.Qt.AlignTop)
		properties = QtGui.QHBoxLayout()
		pl = QtGui.QVBoxLayout()
		op = QtGui.QHBoxLayout()
		op.addWidget(self.open_folder_button)
		self.label2 = QtGui.QLabel('opened folder:')
		op.addWidget(self.label2)
		pl.addLayout(op)
		cl = QtGui.QHBoxLayout()
		label3 = QtGui.QLabel('number of clusters:')
		cl.addWidget(label3)
		cl.addWidget(self.num_of_clusters)
		cl.addStretch(1)
		pl.addLayout(cl)
		pr = QtGui.QVBoxLayout()
		pr.addWidget(lyrics)
		pr.addWidget(chords)
		pr.addWidget(both)
		properties.addLayout(pl)
		properties.addLayout(pr)
		label4 = QtGui.QLabel('results')
		leftLayout.addWidget(label1)
		leftLayout.addLayout(properties)
		leftLayout.addWidget(self.start_button)
		leftLayout.addWidget(label4)
		leftLayout.addWidget(self.cluster_select)
		leftLayout.addWidget(self.results)

		self.mainLayout.addLayout(leftLayout)

		rightLayout = QtGui.QVBoxLayout()
		rightLayout.addWidget(self.canvas)
		rightLayout.addWidget(self.mpl_toolbar)
		self.mainLayout.addLayout(rightLayout)

		self.main_widget = QtGui.QWidget()
		self.main_widget.setLayout(self.mainLayout)
		self.setCentralWidget(self.main_widget)
		self.setWindowTitle('Main App')
		self.setMinimumSize(1200, 700)
		self.files = None
	
	# ファイルをロードするためのメソッド
	def open_folder(self):
		fname = QtGui.QFileDialog.getExistingDirectory(self, 'Open Directory', os.path.expanduser('~' + '/research/Musics'))
		files = glob.glob(str(fname) + '/*')
		self.fname = fname
		self.files = files
		musics = load_data(files)
		self.musics = musics
		self.label2.setText('opened folder: ' + fname)
		self.statusBar().showMessage('opened ' + fname + ' successfully')

	# 多次元尺度構成法 (MDS) によるプロットを行うメソッド
	def plot_mds(self, labels, data):
		leds = [ 'cluster ' + str(i) for i in xrange(self.k) ]
		pt = ['o', '+', 'x', '4']

		mds = manifold.MDS(n_components=2, dissimilarity='euclidean')
		y = mds.fit_transform(data)
		self.fig.delaxes(self.fig.axes[0])
		self.axes = self.fig.add_axes([0.1, 0.1, 0.8, 0.8])
		for i in xrange(self.k):
			dat = y[np.where(labels==i)]
			self.axes.plot(dat[:, 0], dat[:, 1], pt[i/6], label=leds[i])
		self.axes.set_xlim(np.min(y[:, 0]) - 0.5, np.max(y[:, 0]) + 1.5)
		self.axes.set_ylim(np.min(y[:, 1]) - 0.5, np.max(y[:, 1]) + 1.5)
		self.axes.set_title('MDS Scatter Plots')
		self.axes.legend(loc='upper right', fontsize='x-small')
		self.canvas.draw()
	
	# 感情スコアをプロットするメソッド
	@QtCore.pyqtSlot(QtCore.QModelIndex)
	def plot_a_score(self, index):
		checked = self.mode_select.checkedId()
		if checked == 1: return
		
		props = [
			'ecstasy', 'admiration', 'terror', 'amazement',
			'grief', 'loathing', 'rage', 'vigilance',
		]

		self.fig.delaxes(self.fig.axes[0])
		self.axes = self.fig.add_axes([0.1, 0.05, 0.8, 0.8], polar=True)
		cols = [ 
			'yellow', 'lime', 'darkgreen', 'cyan',
			'blue', 'magenta', 'red', 'orange',
			]
		theta = np.pi/2 - np.arange(0.0, 2*np.pi, 2*np.pi/8) - np.pi/16
		score = self.clusters[self.selected_cluster][index.row()].score
		width = np.pi/8 * np.ones(8)

		bars = self.axes.bar(theta, score, width=width, bottom=0.0)

		idx = 0
		for r, bar in zip(score, bars):
			bar.set_facecolor(cols[idx])
			idx += 1

		t = np.arange(0, 2*np.pi, 2*np.pi/8)
		self.axes.set_xticks(t, [])
		self.axes.set_xticklabels([])
		self.axes.set_yticks(np.linspace(0, 1.0, 11))
		yticklabels = ['0.0', '', '', '', '', '0.5', '', '', '', '', '1.0']
		self.axes.set_yticklabels(yticklabels)
		self.axes.set_ylim(0, 1.0)

		for i in xrange(8):
			ang_rad = np.pi/2 -i / 8.0 * 2 * np.pi
			ang_deg = -i / 8.0 * 360
			ha = 'right'
			if ang_rad < np.pi/2 or ang_rad > 3*np.pi/2: ha = 'left'
			self.axes.text(ang_rad, 1.1, props[i], size=20,
				rotation=ang_deg,
				horizontalalignment='center',
				verticalalignment='center'
			)
		self.canvas.draw()

	# 分類結果として確認するクラスタを変更するメソッド
	def select_cluster(self):
		font = QtGui.QFont()
		self.stdItemModel = QtGui.QStandardItemModel(0, 3)
		self.stdItemModel.setHeaderData(0, QtCore.Qt.Horizontal, 'Title')
		self.stdItemModel.setHeaderData(1, QtCore.Qt.Horizontal, 'Artist')
		self.stdItemModel.setHeaderData(2, QtCore.Qt.Horizontal, 'Original Key')
		self.results.setModel(self.stdItemModel)
		self.dat_idx = 0
		selected = int(str(self.cluster_select.currentText()).split()[1])
		self.selected_cluster = selected

		font = QtGui.QFont()
		font.setPointSize(12)
		for music in self.clusters[selected]:
			title = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.title))
			title.setFont(font)
			artist = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.artist))
			artist.setFont(font)
			org = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.keys[0]))
			org.setFont(font)
			self.stdItemModel.setItem(self.dat_idx, 0, title)
			self.stdItemModel.setItem(self.dat_idx, 1, artist)
			self.stdItemModel.setItem(self.dat_idx, 2, org)
			self.dat_idx += 1
		self.results.resizeColumnToContents(0)
		self.results.resizeColumnToContents(1)
		self.results.resizeColumnToContents(2)

	# メインメソッド
	def main(self):
		if self.musics is None:
			qm = QtGui.QMessageBox.critical(self, 'ExectionError', 'No directory is selected!', QtGui.QMessageBox.Ok)
			return
		try:
			k = int(self.num_of_clusters.text())
		except ValueError:
			qm = QtGui.QMessageBox.critical(self, 'ValueError', 'Invalid type for number of clusters!', QtGui.QMessageBox.Ok)
			return
		if k <= 0:
			qm = QtGui.QMessageBox.critical(self, 'ValueError', 'Number of clusters must be a positive integer!', QtGui.QMessageBox.Ok)
			return
		self.stdItemModel.clear()
		self.stdItemModel = QtGui.QStandardItemModel(0, 3)
		self.stdItemModel.setHeaderData(0, QtCore.Qt.Horizontal, 'Title')
		self.stdItemModel.setHeaderData(1, QtCore.Qt.Horizontal, 'Artist')
		self.stdItemModel.setHeaderData(2, QtCore.Qt.Horizontal, 'Original Key')
		self.results.setModel(self.stdItemModel)
		self.k = k
		self.cluster_select.clear()
		for i in xrange(k):
			self.cluster_select.addItem('cluster ' + str(i))
		self.selected_cluster = 0
		
		checked = self.mode_select.checkedId()
		labels = None
		data = None
		if checked == 0:
			labels, data = clustering_by_lyrics(self.musics, k)
		elif checked == 1:
			labels, data = clustering_by_chords(self.musics, k)
		elif checked == 2:
			labels, data = clustering_by_chords_and_lyrics(self.musics, k)
		self.statusBar().showMessage('Finish')
		
		self.plot_mds(labels, data)
		
		self.dat_idx = 0
		clusters = { i:[] for i in xrange(k) }
		for idx, label in enumerate(labels):
			clusters[label].append(self.musics[idx])
		self.clusters = clusters
		
		font = QtGui.QFont()
		font.setPointSize(12)
		for music in clusters[0]:
			title = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.title))
			title.setFont(font)
			artist = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.artist))
			artist.setFont(font)
			org = QtGui.QStandardItem(QtCore.QString.fromLocal8Bit(music.keys[0]))
			org.setFont(font)
			self.stdItemModel.setItem(self.dat_idx, 0, title)
			self.stdItemModel.setItem(self.dat_idx, 1, artist)
			self.stdItemModel.setItem(self.dat_idx, 2, org)
			self.dat_idx += 1
		self.results.resizeColumnToContents(0)
		self.results.resizeColumnToContents(1)
		self.results.resizeColumnToContents(2)
class DensityPanel(FigureCanvasWxAgg):
    def __init__(self, parent, **kwargs):
        self.figure = Figure()
        FigureCanvasWxAgg.__init__(self, parent, -1, self.figure, **kwargs)
        self.canvas = self.figure.canvas
        self.SetMinSize((100,100))
        self.figure.set_facecolor((1,1,1))
        self.figure.set_edgecolor((1,1,1))
        self.canvas.SetBackgroundColour('white')
        self.subplot = self.figure.add_subplot(111)
        self.gate_helper = GatingHelper(self.subplot, self)

        self.navtoolbar = None
        self.point_list = []
        self.gridsize = 50
        self.cb = None
        self.x_scale = LINEAR_SCALE
        self.y_scale = LINEAR_SCALE
        self.color_scale = None
        self.x_label = ''
        self.y_label = ''
        self.cmap ='jet'
        
        self.canvas.mpl_connect('button_release_event', self.on_release)
    
    def setpointslists(self, points):
        self.subplot.clear()
        self.point_list = points        
        plot_pts = np.array(points).astype(float)
        
        if self.x_scale == LOG_SCALE:
            plot_pts = plot_pts[(plot_pts[:,0]>0)]
        if self.y_scale == LOG_SCALE:
            plot_pts = plot_pts[(plot_pts[:,1]>0)]
        
        hb = self.subplot.hexbin(plot_pts[:, 0], plot_pts[:, 1], 
                                 gridsize=self.gridsize,
                                 xscale=self.x_scale,
                                 yscale=self.y_scale,
                                 bins=self.color_scale,
                                 cmap=matplotlib.cm.get_cmap(self.cmap))
        
        if self.cb:
            # Remove the existing colorbar and reclaim the space so when we add
            # a colorbar to the new hexbin subplot, it doesn't get indented.
            self.figure.delaxes(self.figure.axes[1])
            self.figure.subplots_adjust(right=0.90)
        self.cb = self.figure.colorbar(hb)
        if self.color_scale==LOG_SCALE:
            self.cb.set_label('log10(N)')
        
        self.subplot.set_xlabel(self.x_label)
        self.subplot.set_ylabel(self.y_label)
        
        xmin = np.nanmin(plot_pts[:,0])
        xmax = np.nanmax(plot_pts[:,0])
        ymin = np.nanmin(plot_pts[:,1])
        ymax = np.nanmax(plot_pts[:,1])

        # Pad all sides
        if self.x_scale==LOG_SCALE:
            xmin = xmin/1.5
            xmax = xmax*1.5
        else:
            xmin = xmin-(xmax-xmin)/20.
            xmax = xmax+(xmax-xmin)/20.
            
        if self.y_scale==LOG_SCALE:
            ymin = ymin/1.5
            ymax = ymax*1.5
        else:
            ymin = ymin-(ymax-ymin)/20.
            ymax = ymax+(ymax-ymin)/20.

        self.subplot.axis([xmin, xmax, ymin, ymax])
    
        self.reset_toolbar()
    
    def getpointslists(self):
        return self.point_list
    
    def setgridsize(self, gridsize):
        self.gridsize = gridsize

    def set_x_scale(self, scale):
        self.x_scale = scale
    
    def set_y_scale(self, scale):
        self.y_scale = scale
        
    def set_color_scale(self, scale):
        if scale==LINEAR_SCALE:
            scale = None
        self.color_scale = scale

    def set_x_label(self, label):
        self.x_label = label
    
    def set_y_label(self, label):
        self.y_label = label
        
    def set_colormap(self, cmap):
        self.cmap = cmap
        self.draw()

    def get_toolbar(self):
        if not self.navtoolbar:
            self.navtoolbar = NavigationToolbar(self.canvas)
        return self.navtoolbar

    def reset_toolbar(self):
        # Cheat since there is no way reset
        if self.navtoolbar:
            self.navtoolbar._views.clear()
            self.navtoolbar._positions.clear()
            self.navtoolbar.push_current()
    
    def set_configpanel(self,configpanel):
        '''Allow access of the control panel from the plotting panel'''
        self.configpanel = configpanel
        
    def on_release(self, evt):
        if evt.button == 3: # right click
            self.show_popup_menu((evt.x, self.canvas.GetSize()[1]-evt.y), None)
            
    def show_popup_menu(self, (x,y), data):
        self.popup_menu_filters = {}
        popup = wx.Menu()
        loadimages_table_item = popup.Append(-1, 'Create gated table for CellProfiler LoadImages')
        selected_gate = self.configpanel.gate_choice.get_gatename_or_none()
        selected_gates = []
        if selected_gate:
            selected_gates = [selected_gate]
        self.Bind(wx.EVT_MENU, 
                  lambda(e):ui.prompt_user_to_create_loadimages_table(self, selected_gates), 
                  loadimages_table_item)
        
        show_images_in_gate_item = popup.Append(-1, 'Show images in gate')
        show_images_in_gate_item.Enable(selected_gate is not None)
        self.Bind(wx.EVT_MENU, self.show_images_from_gate, show_images_in_gate_item)
        if p.object_table:
            show_objects_in_gate_item = popup.Append(-1, 'Show %s in gate'%(p.object_name[1]))
            show_objects_in_gate_item.Enable(selected_gate is not None)
            self.Bind(wx.EVT_MENU, self.show_objects_from_gate, show_objects_in_gate_item)

        self.PopupMenu(popup, (x,y))
Exemple #5
0
class GraphPanel(wx.Panel):
    """Graph panel draws the runtime graph"""


    def __init__(self,parent):
        wx.Panel.__init__(self,parent)
        self.SetBackgroundColour('#FFFFFF')
        self.SetSizeWH(500,600)
        self.initGraph()

        wx.EVT_PAINT(self, self.OnPaint)
        self.redraw_bars = False
        self.brother = None

    def drawSpans(self,FirstLoad=False):
        """ draws interval spans"""
        global lastTrialDuration
        global  newWaitDuration
        startAt = self.trial-0.5
        h= 1.0

        if self.trial==1:
           startAt=0
           h=1.5
        drawX = 0.0

        del graphStartTimes[:]
        for i in X.intervalList:
            graphStartTimes.append(drawX)
            color = uv.iColors[i.type]
            if isinstance(i, Intervals.ToneInt):
                color = uv.freq2color(i.freq)
                self.axes.bar(drawX, h, 
                              color=color,zorder=0,lw=0.0, width=i.duration, bottom=startAt,)
            else:

                self.axes.bar(drawX, h, 
                              color=color,zorder=0,lw=0.0, width=i.duration, bottom=startAt,)

            drawX+=i.duration #raj-changed the value from i.maxDuration to i.duration to make the graph change dynamically based on lever press


                    
    def initGraph(self):
        """ initalize graph to draw spans """

        self.trial = 1
        self.sbs = {}
        self.sbs['Lever'] = ScatterBrain('Lever','#3399FF','o')
        self.sbs['Mark'] = ScatterBrain('Mark','#000000','x')
        for i in range(0,5):
            name = 'aTaste%d'%i
            self.sbs[name] = ScatterBrain(name,uv.TasteColors[i],'s')
            name2 = 'mTaste%d'%i
            self.sbs[name2] = ScatterBrain(name2,uv.TasteColors[i],'s',False)
        
        self.figure = Figure(dpi=100,figsize=(5,5.5))
        self.axes = self.figure.add_subplot(111)
        print 'X.trial', X.trialDuration
        self.axes.axis([0,X.trialDuration,0,1.5])
        self.axes.set_xlabel('time (s)')
        
        self.drawSpans(True)
        
        LText = FontProperties()
        LText.set_size("small")
        
        
        self.axes.legend((self.sbs['Lever'].getPlot(self.axes),self.sbs['Mark'].getPlot(self.axes),
                          self.sbs['aTaste1'].getPlot(self.axes),self.sbs['mTaste1'].getPlot(self.axes)),
                         ("Lever Press","Time Marked", "Reward","Manual Reward"),
                         prop=LText, fancybox=True, bbox_to_anchor=(0., 1.02, 1., .102), loc=1, ncol=2, mode="expand", borderaxespad=0)
        
        self.canvas = FigureCanvas(self, -1, self.figure)

    def clearGraph(self):
        """ clear graph"""
        self.figure.delaxes(self.axes)
        self.initGraph()
        self.Refresh()
    
    def addPoint(self,i,t,pcat):
        """ add point to a scatter plot
        Args:
            i (int): index of intervals
            t (float): time to point to
            pcat (int): which scatter plot to add point to
        """
        ti = t
        if i!=-1:
            ti+= graphStartTimes[i]
        if pcat<8:
            self.sbs['aTaste%d'%pcat].addPoint(ti,self.trial)
        elif pcat<16:
            self.sbs['mTaste%d'%(pcat-8)].addPoint(ti,self.trial)
        elif pcat==30:
            self.sbs['Lever'].addPoint(ti,self.trial)
        elif pcat==31:
            self.sbs['Mark'].addPoint(ti,self.trial)
    
    def shiftPoints(self, offset):
        """ Move points """
        lvlen = len(self.sbs['Lever'].x)
        r = range(0,lvlen)
        r.reverse()
        for i in r:
            if self.sbs['Lever'].y[i]==self.trial:
                self.sbs['Lever'].x[i]-= offset
            else:
                break
    
    def newTrial(self):
        """ prepare graph for new trial"""
        self.trial+=1
        self.axes.set_ylim(top=(self.trial+0.5))
        self.redraw_bars = True
        
    def OnPaint(self, event):
        """ Redraw """
        """
        if self.redraw_bars:
            self.redraw_bars = False
            self.drawSpans()
        for k,v in self.sbs.items():
            v.getPlot(self.axes)
            del v.x[:]
            del v.y[:]
        self.canvas.draw() """
        d = DrawThread(self)
        d.start()
        event.Skip()

    def OnSetFocus(self, event):
        self.color = 'yellow'
        self.Refresh()

    def OnKillFocus(self, event):
        self.color = '#b3b3b3'
        self.Refresh()
    
    def saveGraph(self,filename="graph.png"):
        """Save graph as file"""
        self.figure.savefig(filename)
Exemple #6
0
class PyAbel:  #(tk.Tk):
    def __init__(self, parent):
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.fn = None
        self.old_fn = None
        self.old_method = None
        self.old_fi = None
        self.AIM = None
        self.rmx = (368, 393)

        # matplotlib figure
        self.f = Figure(figsize=(2, 6))
        self.gs = gridspec.GridSpec(2, 2, width_ratios=[1, 2])
        self.gs.update(wspace=0.2, hspace=0.2)

        self.plt = []
        self.plt.append(self.f.add_subplot(self.gs[0]))
        self.plt.append(self.f.add_subplot(self.gs[1]))
        self.plt.append(
            self.f.add_subplot(self.gs[2],
                               sharex=self.plt[0],
                               sharey=self.plt[0]))
        self.plt.append(self.f.add_subplot(self.gs[3]))
        for i in [0, 2]:
            self.plt[i].set_adjustable('box-forced')

        # hide until have data
        for i in range(4):
            self.plt[i].axis("off")

        # tkinter
        # set default font size for buttons
        self.font = tkFont.Font(size=11)
        self.fontB = tkFont.Font(size=12, weight='bold')

        #frames top (buttons), text, matplotlib (canvas)
        self.main_container = tk.Frame(self.parent, height=10, width=100)
        self.main_container.pack(side="top", fill="both", expand=True)

        self.button_frame = tk.Frame(self.main_container)
        #self.info_frame = tk.Frame(self.main_container)
        self.matplotlib_frame = tk.Frame(self.main_container)

        self.button_frame.pack(side="top", fill="x", expand=True)
        #self.info_frame.pack(side="top", fill="x", expand=True)
        self.matplotlib_frame.pack(side="top", fill="both", expand=True)

        self._menus()
        self._button_area()
        self._plot_canvas()
        self._text_info_box()

    def _button_frame(self):
        self.button_frame = tk.Frame(self.main_container)
        self.button_frame.pack(side="top", fill="x", expand=True)
        self._menus()

    def _menus(self):
        # menus with callback ----------------
        # duplicates the button interface
        self.menubar = tk.Menu(self.parent)
        self.transform_method = tk.IntVar()
        self.center_method = tk.IntVar()

        # File - menu
        self.filemenu = tk.Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="Load image file",
                                  command=self._loadimage)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Exit", command=self._quit)
        self.menubar.add_cascade(label="File", menu=self.filemenu)

        # Process - menu
        self.processmenu = tk.Menu(self.menubar, tearoff=0)
        #self.processmenu.add_command(label="Center image", command=self._center)

        self.subcent = tk.Menu(self.processmenu)
        for cent in center_methods:
            self.subcent.add_radiobutton(label=cent,
                                         var=self.center_method,
                                         val=center_methods.index(cent),
                                         command=self._center)
        self.processmenu.add_cascade(label="Center image",
                                     menu=self.subcent,
                                     underline=0)

        self.submenu = tk.Menu(self.processmenu)
        for method in Abel_methods:
            self.submenu.add_radiobutton(label=method,
                                         var=self.transform_method,
                                         val=Abel_methods.index(method),
                                         command=self._transform)
        self.processmenu.add_cascade(label="Inverse Abel transform",
                                     menu=self.submenu,
                                     underline=0)

        self.processmenu.add_command(label="Speed distribution",
                                     command=self._speed)
        self.processmenu.add_command(label="Angular distribution",
                                     command=self._anisotropy)
        self.angmenu = tk.Menu(self.processmenu)
        self.menubar.add_cascade(label="Processing", menu=self.processmenu)

        # view - menu
        self.viewmenu = tk.Menu(self.menubar, tearoff=0)
        self.viewmenu.add_command(label="Raw image", command=self._display)
        self.viewmenu.add_command(label="Inverse Abel transformed image",
                                  command=self._transform)
        self.viewmenu.add_command(label="view buttons",
                                  command=self._on_buttons)
        self.menubar.add_cascade(label="View", menu=self.viewmenu)

    def _button_area(self):
        # grid layout
        # make expandable
        for col in range(5):
            self.button_frame.columnconfigure(col, weight=1)
            self.button_frame.rowconfigure(col, weight=1)

        # column 0 ---------
        # load image file button
        self.load = tk.Button(master=self.button_frame,
                              text="load image",
                              font=self.fontB,
                              fg="dark blue",
                              command=self._loadimage)
        self.load.grid(row=0, column=0, sticky=tk.W, padx=(5, 10), pady=(5, 0))
        self.sample_image = ttk.Combobox(master=self.button_frame,
                                         font=self.font,
                                         values=[
                                             "from file", "from transform",
                                             "sample dribinski",
                                             "sample Ominus"
                                         ],
                                         width=14,
                                         height=4)
        self.sample_image.current(0)
        self.sample_image.grid(row=1, column=0, padx=(5, 10))

        # quit
        self.quit = tk.Button(master=self.button_frame,
                              text="Quit",
                              font=self.fontB,
                              fg="dark red",
                              command=self._quit)
        self.quit.grid(row=3, column=0, sticky=tk.W, padx=(5, 10), pady=(0, 5))

        # column 1 -----------
        # center image
        self.center = tk.Button(master=self.button_frame,
                                text="center image",
                                anchor=tk.W,
                                font=self.fontB,
                                fg="dark blue",
                                command=self._center)
        self.center.grid(row=0, column=1, padx=(0, 20), pady=(5, 0))
        self.center_method = ttk.Combobox(master=self.button_frame,
                                          font=self.font,
                                          values=center_methods,
                                          width=11,
                                          height=4)
        self.center_method.current(1)
        self.center_method.grid(row=1, column=1, padx=(0, 20))

        # column 2 -----------
        # Abel transform image
        self.recond = tk.Button(master=self.button_frame,
                                text="Abel transform image",
                                font=self.fontB,
                                fg="dark blue",
                                command=self._transform)
        self.recond.grid(row=0, column=2, padx=(0, 10), pady=(5, 0))

        self.transform = ttk.Combobox(master=self.button_frame,
                                      values=Abel_methods,
                                      font=self.font,
                                      width=10,
                                      height=len(Abel_methods))
        self.transform.current(2)
        self.transform.grid(row=1, column=2, padx=(0, 20))

        self.direction = ttk.Combobox(master=self.button_frame,
                                      values=["inverse", "forward"],
                                      font=self.font,
                                      width=8,
                                      height=2)
        self.direction.current(0)
        self.direction.grid(row=2, column=2, padx=(0, 20))

        # column 3 -----------
        # speed button
        self.speed = tk.Button(master=self.button_frame,
                               text="speed",
                               font=self.fontB,
                               fg="dark blue",
                               command=self._speed)
        self.speed.grid(row=0, column=5, padx=20, pady=(5, 0))

        self.speedclr = tk.Button(master=self.button_frame,
                                  text="clear plot",
                                  font=self.font,
                                  command=self._speed_clr)
        self.speedclr.grid(row=1, column=5, padx=20)

        # column 4 -----------
        # anisotropy button
        self.aniso = tk.Button(master=self.button_frame,
                               text="anisotropy",
                               font=self.fontB,
                               fg="dark blue",
                               command=self._anisotropy)
        self.aniso.grid(row=0, column=6, pady=(5, 0))

        self.subframe = tk.Frame(self.button_frame)
        self.subframe.grid(row=1, column=6)
        self.rmin = tk.Entry(master=self.subframe,
                             text='rmin',
                             width=3,
                             font=self.font)
        self.rmin.grid(row=0, column=0)
        self.rmin.delete(0, tk.END)
        self.rmin.insert(0, self.rmx[0])
        self.lbl = tk.Label(master=self.subframe, text="to", font=self.font)
        self.lbl.grid(row=0, column=1)
        self.rmax = tk.Entry(master=self.subframe,
                             text='rmax',
                             width=3,
                             font=self.font)
        self.rmax.grid(row=0, column=2)
        self.rmax.delete(0, tk.END)
        self.rmax.insert(0, self.rmx[1])

        # turn off button interface
        self.hide_buttons = tk.Button(master=self.button_frame,
                                      text="hide buttons",
                                      font=self.fontB,
                                      fg='grey',
                                      command=self._hide_buttons)
        self.hide_buttons.grid(row=3, column=6, sticky=tk.E, pady=(0, 20))

    def _text_info_box(self):
        # text info box ---------------------
        self.text = ScrolledText(master=self.button_frame,
                                 height=6,
                                 fg="mediumblue",
                                 bd=1,
                                 relief=tk.SUNKEN)
        self.text.insert(
            tk.END, "Work in progress, some features may"
            " be incomplete ...\n")
        self.text.insert(
            tk.END, "To start: load an image data file using"
            " e.g. data/O2-ANU1024.txt.bz2\n"
            " (1) load image button (or file menu)\n"
            " (2) center image\n"
            " (3) Abel transform\n"
            " (4) speed\n"
            " (5) anisotropy\n"
            " (6) Abel transform <- change\n"
            " (:) repeat\n")
        self.text.grid(row=3, column=1, columnspan=3, padx=5)

    def _plot_canvas(self):
        # matplotlib canvas --------------------------
        self.canvas = FigureCanvasTkAgg(self.f, master=self.matplotlib_frame)
        #self.cid = self.canvas.mpl_connect('button_press_event', self._onclick)

        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.parent)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(anchor=tk.W,
                                   side=tk.TOP,
                                   fill=tk.BOTH,
                                   expand=1)

    def _onclick(self, event):
        print('button={:d}, x={:f}, y={:f}, xdata={:f}, ydata={:f}'.format(
            event.button, event.x, event.y, event.xdata, event.ydata))

    # call back functions -----------------------
    def _display(self):
        if self.fn is None:
            self._loadimage()

        # display image
        self.plt[0].imshow(self.IM, vmin=0)
        #rows, cols = self.IM.shape
        #r2 = rows/2
        #c2 = cols/2
        #self.a.plot((r2, r2), (0, cols), 'r--', lw=0.1)
        #self.a.plot((0, rows), (c2, c2),'r--', lw=0.1)
        #self.f.colorbar(self.a.get_children()[2], ax=self.f.gca())
        self.plt[0].set_title("raw image", fontsize=10)
        self.canvas.show()

    def _loadimage(self):

        if self.fn is not None:
            # clear old plot
            for i in range(4):
                self._clr_plt(i)
                self.plt[i].axis("off")

        self.fn = self.sample_image.get()
        # update what is occurring text box
        self.text.insert(tk.END, "\nloading image file {:s}".format(self.fn))
        self.text.see(tk.END)
        self.canvas.show()

        if self.fn == "from file":
            self.fn = askopenfilename()
            # read image file
            if ".txt" in self.fn:
                self.IM = np.loadtxt(self.fn)
            else:
                self.IM = imread(self.fn)
        elif self.fn == "from transform":
            self.IM = self.AIM
            self.AIM = None
            for i in range(1, 4):
                self._clr_plt(i)
                self.plt[i].axis("off")
            self.direction.current(0)
        else:
            self.fn = self.fn.split(' ')[-1]
            self.IM = abel.tools.analytical.sample_image(n=1001, name=self.fn)
            self.direction.current(1)  # raw images require 'forward' transform
            self.text.insert(tk.END,
                             "\nsample image: (1) Abel transform 'forward', ")
            self.text.insert(tk.END,
                             "              (2) load 'from transform', ")
            self.text.insert(tk.END,
                             "              (3) Abel transform 'inverse', ")
            self.text.insert(tk.END, "              (4) Speed")
            self.text.see(tk.END)

        # if even size image, make odd
        if self.IM.shape[0] % 2 == 0:
            self.IM = shift(self.IM, (-0.5, -0.5))[:-1, :-1]

        self.old_method = None
        self.AIM = None
        self.action = "file"
        self.rmin.delete(0, tk.END)
        self.rmin.insert(0, self.rmx[0])
        self.rmax.delete(0, tk.END)
        self.rmax.insert(0, self.rmx[1])

        # show the image
        self._display()

    def _center(self):
        self.action = "center"

        center_method = self.center_method.get()
        # update information text box
        self.text.insert(tk.END, "\ncentering image using {:s}".\
                         format(center_method))
        self.canvas.show()

        # center image via chosen method
        self.IM = abel.tools.center.center_image(self.IM,
                                                 center=center_method,
                                                 odd_size=True)
        #self.text.insert(tk.END, "\ncenter offset = {:}".format(self.offset))
        self.text.see(tk.END)

        self._display()

    def _transform(self):
        #self.method = Abel_methods[self.transform_method.get()]
        self.method = self.transform.get()
        self.fi = self.direction.get()

        if self.method != self.old_method or self.fi != self.old_fi:
            # Abel transform of whole image
            self.text.insert(tk.END,"\n{:s} {:s} Abel transform:".\
                             format(self.method, self.fi))
            if self.method == "basex":
                self.text.insert(
                    tk.END, "\nbasex: first time calculation of the basis"
                    " functions may take a while ...")
            elif self.method == "direct":
                self.text.insert(
                    tk.END,
                    "\ndirect: calculation is slowed if Cython unavailable ..."
                )
            self.canvas.show()

            if self.method == 'linbasex':
                self.AIM = abel.Transform(
                    self.IM,
                    method=self.method,
                    direction=self.fi,
                    transform_options=dict(return_Beta=True))
            else:
                self.AIM = abel.Transform(
                    self.IM,
                    method=self.method,
                    direction=self.fi,
                    transform_options=dict(basis_dir='bases'),
                    symmetry_axis=None)
            self.rmin.delete(0, tk.END)
            self.rmin.insert(0, self.rmx[0])
            self.rmax.delete(0, tk.END)
            self.rmax.insert(0, self.rmx[1])

        if self.old_method != self.method or self.fi != self.old_fi or\
           self.action not in ["speed", "anisotropy"]:
            self.plt[2].set_title(self.method +
                                  " {:s} Abel transform".format(self.fi),
                                  fontsize=10)
            self.plt[2].imshow(self.AIM.transform,
                               vmin=0,
                               vmax=self.AIM.transform.max() / 5.0)
            #self.f.colorbar(self.c.get_children()[2], ax=self.f.gca())
            #self.text.insert(tk.END, "{:s} inverse Abel transformed image".format(self.method))

        self.text.see(tk.END)
        self.old_method = self.method
        self.old_fi = self.fi
        self.canvas.show()

    def _speed(self):
        self.action = "speed"
        # inverse Abel transform
        self._transform()
        # update text box in case something breaks
        self.text.insert(tk.END, "\nspeed distribution")
        self.text.see(tk.END)
        self.canvas.show()

        if self.method == 'linbasex':
            self.speed_dist = self.AIM.Beta[0]
            self.radial = self.AIM.radial
        else:
            # speed distribution
            self.radial, self.speed_dist = abel.tools.vmi.angular_integration(
                self.AIM.transform)

        self.plt[1].axis("on")
        self.plt[1].plot(self.radial,
                         self.speed_dist / self.speed_dist[10:].max(),
                         label=self.method)
        # make O2- look nice
        if self.fn.find('O2-ANU1024') > -1:
            self.plt[1].axis(xmax=500, ymin=-0.05)
        elif self.fn.find('VMI_art1') > -1:
            self.plt[1].axis(xmax=260, ymin=-0.05)

        self.plt[1].set_xlabel("radius (pixels)", fontsize=9)
        self.plt[1].set_ylabel("normalized intensity")
        self.plt[1].set_title("radial speed distribution", fontsize=12)
        self.plt[1].legend(fontsize=9, loc=0, frameon=False)

        self.action = None
        self.canvas.show()

    def _speed_clr(self):
        self._clr_plt(1)

    def _clr_plt(self, i):
        self.f.delaxes(self.plt[i])
        self.plt[i] = self.f.add_subplot(self.gs[i])
        self.canvas.show()

    def _anisotropy(self):
        def P2(x):  # 2nd order Legendre polynomial
            return (3 * x * x - 1) / 2

        def PAD(theta, beta, amp):
            return amp * (1 + beta * P2(np.cos(theta)))

        self.action = "anisotropy"
        self._transform()

        if self.method == 'linbasex':
            self.text.insert(tk.END,
                        "\nanisotropy parameter pixel range 0 to {}: "\
                        .format(self.rmx[1]))
        else:
            # radial range over which to follow the intensity variation with angle
            self.rmx = (int(self.rmin.get()), int(self.rmax.get()))
            self.text.insert(tk.END,
                        "\nanisotropy parameter pixel range {:} to {:}: "\
                        .format(*self.rmx))
        self.canvas.show()

        # inverse Abel transform
        self._transform()

        if self.method == 'linbasex':
            self.beta = self.AIM.Beta[1]
            self.radial = self.AIM.radial
            self._clr_plt(3)
            self.plt[3].axis("on")
            self.plt[3].plot(self.radial, self.beta, 'r-')
            self.plt[3].set_title("anisotropy", fontsize=12)
            self.plt[3].set_xlabel("radius", fontsize=9)
            self.plt[3].set_ylabel("anisotropy parameter")
            # make O2- look nice
            if self.fn.find('O2-ANU1024') > -1:
                self.plt[3].axis(xmax=500, ymin=-1.1, ymax=0.1)
            elif self.fn.find('VMI_art1') > -1:
                self.plt[3].axis(xmax=260, ymin=-1.1, ymax=2)
        else:
            # intensity vs angle
            self.beta, self.amp, self.rad, self.intensity, self.theta =\
               abel.tools.vmi.radial_integration(self.AIM.transform,\
                                                 radial_ranges=[self.rmx,])

            self.text.insert(tk.END,
                             " beta = {:g}+-{:g}".format(*self.beta[0]))

            self._clr_plt(3)
            self.plt[3].axis("on")

            self.plt[3].plot(self.theta, self.intensity[0], 'r-')
            self.plt[3].plot(self.theta,
                             PAD(self.theta, self.beta[0][0], self.amp[0][0]),
                             'b-',
                             lw=2)
            self.plt[3].annotate(
                "$\\beta({:d},{:d})={:.2g}\pm{:.2g}$".format(*self.rmx +
                                                             self.beta[0]),
                (-3, self.intensity[0].min() / 0.8))
            self.plt[3].set_title("anisotropy", fontsize=12)
            self.plt[3].set_xlabel("angle", fontsize=9)
            self.plt[3].set_ylabel("intensity")

        self.action = None
        self.canvas.show()

    def _hide_buttons(self):
        self.button_frame.destroy()

    def _on_buttons(self):
        self._button_frame()

    def _quit(self):
        self.parent.quit()  # stops mainloop
        self.parent.destroy()  # this is necessary on Windows to prevent
Exemple #7
0
class MplCanvas(FigureCanvas):
    subscriptions = [rc.MT_PING, MT_EXIT,
                     rc.MT_TASK_STATE_CONFIG,
                     rc.MT_ROBOT_CONTROL_SPACE_ACTUAL_STATE,
                     rc.MT_GROBOT_SEGMENT_PERCEPTS,
                     rc.MT_GROBOT_RAW_FEEDBACK,
                     rc.MT_END_TASK_STATE]

    def __init__(self, parent=None, width=8, height=10, dpi=80):
        self.parent = parent
        self.paused = False
        self.LiveData = None
        self.fdbk_actual_pos = None
        self.fdbk_actual_cori = None
        self.tsc_mdf = None
        self.ets_mdf = None
        self.fdbk_percepts = [0] * 16
        self.fdbk_torques = [0] * 16
        self.redraw_yticks = True

        self.figure = Figure(figsize=(width, height), dpi=dpi, facecolor='#bbbbbb')
        FigureCanvas.__init__(self, self.figure)

        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
        

    def init_judge_display(self):
        N = self.config['config']['number_of_data_points']

        self.LiveData = {'ActualPos': {},
                         'ThreshUpper': {},
                         'ThreshLower': {},
                         'JudgingMethod': {},
                         'JudgingPolarity': {},
                         'max_scale': {},
                         'min_scale': {} }
        
        allDims = 1 + 1 + 10 + 15 + 28  # trans + ori + finger + force + torque
        
        for d in range(allDims):
            self.LiveData['ActualPos'][d] = np.zeros(N)
            self.LiveData['ThreshUpper'][d] = nan_array(N)
            self.LiveData['ThreshLower'][d] = nan_array(N)
            self.LiveData['JudgingMethod'][d] = nan_array(N)
            self.LiveData['JudgingPolarity'][d] = nan_array(N)
            self.LiveData['max_scale'][d] = np.finfo(float).eps
            self.LiveData['min_scale'][d] = -np.finfo(float).eps #

        self.LiveData['TaskStateNo'] = np.zeros(N)
        self.LiveData['TaskStateVerdict'] = np.ones(N)

    def run(self, config_file, server):
        self.mod = RTMA_Module(0, 0)
        self.mod.ConnectToMMM(server)
        for sub in self.subscriptions:
            self.mod.Subscribe(sub)
        self.mod.SendModuleReady()
        print "Connected to RTMA at", server

        self.config_file = config_file
        self.load_config()

        self.init_judge_display()
        self.init_plot()
        self.init_legend()

        timer = QtCore.QTimer(self)
        QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), self.timer_event)
        timer.start(10)     

    def update_scales(self, d):
        min_data = np.nanmin(self.LiveData['ActualPos'][d])
        if min_data < self.LiveData['min_scale'][d]:
            self.LiveData['min_scale'][d] = min_data;

        max_data = np.nanmax(self.LiveData['ActualPos'][d])
        if max_data > self.LiveData['max_scale'][d]:
            self.LiveData['max_scale'][d] = max_data;
    
    
    def update_judging_data(self):
        # this loop is so we can update finger pos data even if we haven't
        # received any TASK_STATE_CONFIG msg
        for i in range(self.nDims):
            d = self.dims[i] - 1
            if d > 1:        # fingers
                finger_idx = d-2
                actual_pos = self.fdbk_actual_pos[8+finger_idx];
                self.LiveData['ActualPos'][d] = self.add_to_windowed_array(self.LiveData['ActualPos'][d], actual_pos)
                self.update_scales(d)

        if self.tsc_mdf is None:
            return

        trans_thresh = self.tsc_mdf.trans_threshold
        ori_threshold = self.tsc_mdf.ori_threshold
        finger_thresh = np.array(self.tsc_mdf.finger_threshold, dtype=float)
        finger_dofs_to_judge = np.where(~np.isnan(finger_thresh)==True)[0]

        for i in range(self.nDims):
            d = self.dims[i] - 1

            threshU = np.NAN
            threshL = np.NAN
            method = np.NAN
            polarity = np.NAN

            if d == 0:   # trans
                tgt_pos = np.array(self.tsc_mdf.target[0:3])
                act_pos = np.array(self.fdbk_actual_pos[0:3])
                tgt_disp = tgt_pos - act_pos;
                tgt_dist = np.sqrt(np.sum(np.power(tgt_disp,2)))

                self.LiveData['ActualPos'][d] = self.add_to_windowed_array(self.LiveData['ActualPos'][d], tgt_dist)
                self.update_scales(d)
                
                threshU = trans_thresh
                threshL = -trans_thresh
                method = 1      # dist
                polarity = 2    # less than (inverted)

            elif d == 1: # ori
            
                tgt_cori = np.array(self.tsc_mdf.coriMatrix).reshape((3,3)).T
                act_cori = np.array(self.fdbk_actual_cori).reshape((3,3)).T
                cori_diff_matrix = tgt_cori * act_cori.T
                [diff_rotaxis, diff_angle] = rotmat2rotvec( cori_diff_matrix)

                self.LiveData['ActualPos'][d] = self.add_to_windowed_array(self.LiveData['ActualPos'][d], diff_angle)
                self.update_scales(d)
                
                print diff_angle
                print ori_threshold
                print "-----"

                threshU = ori_threshold
                threshL = -ori_threshold
                method = 1      # dist
                polarity = 2    # less than (inverted)

            else:        # fingers
                finger_idx = d-2
                if np.where(finger_dofs_to_judge == finger_idx)[0].size > 0:

                    thresh = self.tsc_mdf.finger_threshold[finger_idx]
                    method = self.tsc_mdf.finger_threshold_judging_method[finger_idx]
                    polarity = self.tsc_mdf.finger_threshold_judging_polarity[finger_idx]

                    # invert polarities (because we plot "keep out" zones)
                    if (polarity > 0) and (self.tsc_mdf.timed_out_conseq == 0):
                        polarity = ~polarity & 3;

                    # finger_threshold_judging_method: 1=distance (default), 2=absolute
                    if method == 1:  # dist
                        target = self.tsc_mdf.target[8+finger_idx]
                        threshU = target + thresh
                        threshL = target - thresh
                    else:            # abs
                        threshU = thresh
                
            # insert new data to plotting arrays
            self.LiveData['ThreshUpper'][d] = self.add_to_windowed_array(self.LiveData['ThreshUpper'][d], threshU)
            self.LiveData['ThreshLower'][d] = self.add_to_windowed_array(self.LiveData['ThreshLower'][d], threshL)
            self.LiveData['JudgingMethod'][d] = self.add_to_windowed_array(self.LiveData['JudgingMethod'][d], method)
            self.LiveData['JudgingPolarity'][d] = self.add_to_windowed_array(self.LiveData['JudgingPolarity'][d], polarity)

        self.LiveData['TaskStateNo'] = self.add_to_windowed_array(self.LiveData['TaskStateNo'], self.tsc_mdf.id)

        if self.ets_mdf is not None:
            self.LiveData['TaskStateVerdict'][-2] = self.ets_mdf.outcome
            self.LiveData['TaskStateVerdict'][-1] = self.ets_mdf.outcome
            self.LiveData['TaskStateVerdict'] = self.add_to_windowed_array(self.LiveData['TaskStateVerdict'], self.ets_mdf.outcome)
            self.ets_mdf = None
        else:
            self.LiveData['TaskStateVerdict'] = self.add_to_windowed_array(self.LiveData['TaskStateVerdict'], 1)

    def add_to_windowed_array(self, arr, data):
        arr = np.append(arr, data)
        arr = np.delete(arr, 0)
        return arr

    def load_config(self):
        self.config = ConfigObj(self.config_file, unrepr=True)

    def reload_config(self):
        self.load_config()
        for ax in self.figure.axes:
            self.figure.delaxes(ax)
        self.figure.clear()
        self.draw()
        self.init_plot(True)
        self.init_legend()
        self.redraw_yticks = True

 
    def init_plot(self, clear=False):
        self.figure.subplots_adjust(bottom=.05, right=.98, left=.08, top=.98, hspace=0.07)
        
        trans_dim = 0
        if 'plot_translation' in self.config['config']:
            trans_dim = self.config['config']['plot_translation']
       
        ori_dim = 0
        if 'plot_orientation' in self.config['config']:
            ori_dim = self.config['config']['plot_orientation']
            
        finger_dims = []
        if 'active_finger_dims' in self.config['config']:
            finger_dims = self.config['config']['active_finger_dims'] 
        
        force_dims = []
        if 'active_force_dims' in self.config['config']:
            force_dims = self.config['config']['active_force_dims'] 

        torque_dims = []
        if 'active_torque_dims' in self.config['config']:
            torque_dims = self.config['config']['active_torque_dims'] 
        
        axis_labels = []
        self.dims = []
        if trans_dim == 1:
            self.dims.append(1)
            axis_labels.extend(['XYZ tgt dist'])
        if ori_dim == 1:
            self.dims.append(2)
            axis_labels.extend(['ORI tgt dist'])
        if finger_dims:
            for f in finger_dims:
                if (f>0) and (f<=10):
                    self.dims.extend([f+2])
                    axis_labels.extend(['finger #%d' % f])
                else:
                    print "Warning: invalid finger dim specified: %f, skipping.." % f
        if force_dims:
            force_labels = ['ifx', 'ify', 'ifz', 'mfx', 'mfy', 'mfz', 'rfx', \
                            'rfy', 'rfz', 'lfx', 'lfy', 'lfz', 'tfx', 'tfy', 'tfz']
            for f in force_dims:
                if (f>0) and (f<=15):
                    self.dims.extend([f+12])
                    axis_labels.extend(['force #%d (%s)' % (f, force_labels[f-1])])
                else:
                    print "Warning: invalid force dim specified: %d, skipping.." % f
        if torque_dims:
            for f in torque_dims:
                if (f>0) and (f<=28):
                    self.dims.extend([f+27])
                    axis_labels.extend(['trq #%d' % f])
                else:
                    print "Warning: invalid torque dim specified: %d, skipping.." % f
      
        self.nDims = trans_dim + ori_dim + len(finger_dims) + len(force_dims) + len(torque_dims)
        self.xN = self.config['config']['number_of_data_points']
        self.bg = self.config['marked_task_states'].keys()

        self.max_scale = self.config['config']['max_scale']
        if len(self.max_scale) < self.nDims:
            self.max_scale.extend([np.finfo(float).eps] * (self.nDims - len(self.max_scale)))
        
        self.min_scale = self.config['config']['min_scale']
        if len(self.min_scale) < self.nDims:
            self.min_scale.extend([-np.finfo(float).eps] * (self.nDims - len(self.min_scale)))
        

        self.ax = []
        self.old_size = []
        self.ax_bkg = []
        self.finger_pos = []
        self.zones = {}
        self.zone_idx = []

        for d in range(self.nDims):
            ax = self.figure.add_subplot(self.nDims,1,d+1)
            self.reset_axis(ax, axis_labels[d])
            self.draw()
            
            bbox_width = ax.bbox.width
            bbox_height = ax.bbox.height
            if clear == True:
                # force to redraw
                bbox_width = 0  
                bbox_height = 0

            self.old_size.append( (bbox_width, bbox_height) )
            self.ax_bkg.append(self.copy_from_bbox(ax.bbox))

            line, = ax.plot([], [], 'k-', lw=1.0, aa=None, animated=True)
            line.set_xdata(range(self.xN))
            line.set_ydata([0.0]*self.xN)
            self.finger_pos.append(line)
            self.draw()
    
            self.zones[d] = []
            self.zone_idx.append(0)
            for z in range(60):
                patch = ax.add_patch(Polygon([[0, 1e-12],[1e-12, 0],[1e-12, 1e-12],[0, 1e-12]], fc='none', ec='none', fill=True, closed=True, aa=None, animated=True))
                self.zones[d].append(patch)
                self.draw()

            self.ax.append(ax)


    def reset_axis(self, ax, label):
        ax.grid(True)
        ax.set_xlim(0, self.xN-1)
        ax.set_autoscale_on(False)
        ax.set_ylabel(label, fontsize='small')
        ax.get_xaxis().set_ticks([])
        ax.yaxis.set_major_formatter(FormatStrFormatter('%.02f'))
        for tick in ax.get_yticklabels():
            tick.set_fontsize(9) 

        
    def init_legend(self):
        legnd = []

        line = matplotlib.lines.Line2D([0,0], [0,0], color='k')
        legnd.append(line)

        for d in range(len(self.bg)):
            b_color = self.config['marked_task_states'][self.bg[d]]['color']
            patch = Polygon([[0,0],[0, 0],[0, 0],[0, 0]], fc=b_color, ec='none', fill=True, closed=True, alpha=0.65)
            legnd.append(patch)

        self.figure.legend(legnd, ['Position']+self.bg, loc='lower center', frameon=False, ncol=20, prop={'size':'11'}, columnspacing=.5)
        self.draw()
        
        
    def plot_bg_mask(self, ax, idx, x, mask, ylim, fc, ec, hatch, alpha):
        # Find starts and ends of contiguous regions of true values in mask because
        # we want just one patch object per contiguous region
        _mask = np.asarray(np.insert(mask, 0, 0), dtype=int)
        begin_indices = np.where( np.diff( _mask) == 1)[0]

        _mask = np.asarray(np.append(mask, 0), dtype=int)
        end_indices = np.where( np.diff( _mask) == -1)[0]

        # Get DeltaX
        dx = np.mean( np.diff(x))

        # Get YLim if it was not given
        if len(ylim) == 0:
            ylim = ax.get_ylim()

        z = self.zones[idx]
        a = self.zone_idx[idx]

        for i in range(len( begin_indices)):
            b = begin_indices[i]
            e = end_indices[i]
            xb = x[b] - dx/2;
            xe = x[e] + dx/2;
            
            patch = z[a]
            patch.set_xy([[xb, ylim[0]],[xe, ylim[0]],[xe, ylim[1]],[xb, ylim[1]]])
            patch.set_edgecolor(ec)
            patch.set_facecolor(fc)
            patch.set_hatch(hatch)
            patch.set_alpha(alpha)

            ax.draw_artist(patch)
            a = a + 1
            
        self.zone_idx[idx] = a


    def timer_event(self):
        done = False
        while not done:
            msg = CMessage()
            rcv = self.mod.ReadMessage(msg, 0)
            if rcv == 1:
                msg_type = msg.GetHeader().msg_type

                if msg_type == rc.MT_TASK_STATE_CONFIG:
                    self.tsc_mdf = rc.MDF_TASK_STATE_CONFIG()
                    copy_from_msg(self.tsc_mdf, msg)

                elif msg_type == rc.MT_ROBOT_CONTROL_SPACE_ACTUAL_STATE:
                    mdf = rc.MDF_ROBOT_CONTROL_SPACE_ACTUAL_STATE()
                    copy_from_msg(mdf, msg)

                    self.fdbk_actual_cori = mdf.CoriMatrix

                    self.fdbk_actual_pos = []
                    self.fdbk_actual_pos.extend(mdf.pos)
                    self.fdbk_actual_pos.extend(self.fdbk_percepts)
                    self.fdbk_actual_pos.extend(self.fdbk_torques)
                   
                    self.update_judging_data()

                elif msg_type == rc.MT_GROBOT_SEGMENT_PERCEPTS:
                    mdf = rc.MDF_GROBOT_SEGMENT_PERCEPTS()
                    copy_from_msg(mdf, msg)
                    self.fdbk_percepts = []
                    self.fdbk_percepts.extend(mdf.ind_force[:])
                    self.fdbk_percepts.extend(mdf.mid_force[:]) 
                    self.fdbk_percepts.extend(mdf.rng_force[:]) 
                    self.fdbk_percepts.extend(mdf.lit_force[:]) 
                    self.fdbk_percepts.extend(mdf.thb_force[:])

                elif msg_type == rc.MT_GROBOT_RAW_FEEDBACK:
                    mdf = rc.MDF_GROBOT_RAW_FEEDBACK()
                    copy_from_msg(mdf, msg)
                    self.fdbk_torques = mdf.j_trq
                    
                elif msg_type == rc.MT_END_TASK_STATE:
                    self.ets_mdf = rc.MDF_END_TASK_STATE()
                    copy_from_msg(self.ets_mdf, msg)

                elif msg_type == rc.MT_PING:
                    respond_to_ping(self.mod, msg, 'SimpleJudgeDisplay')

                elif msg_type == MT_EXIT:
                    self.exit()
                    done = True
                    
            else:
                done = True

        self.update_plot()
        
        
        
    def update_plot(self):
        if self.paused == False:
            LiveData = self.LiveData
        else:
            LiveData = self.PausedData

        for i in range(self.nDims):
            ax = self.ax[i]
            d = self.dims[i] - 1

            current_size = ax.bbox.width, ax.bbox.height
            if self.old_size[i] != current_size:
                self.old_size[i] = current_size
                self.draw()
                self.ax_bkg[i] = self.copy_from_bbox(ax.bbox)

            self.restore_region(self.ax_bkg[i])

            self.zone_idx[i] = 0
            
            min_scale = LiveData['min_scale'][d];
            if 'min_scale' in self.config['config']:
                min_scale = self.min_scale[i]
            max_scale = LiveData['max_scale'][d];
            if 'max_scale' in self.config['config']:
                max_scale = self.max_scale[i]
            ax.set_ylim(min_scale, max_scale)
            yLimG = ax.get_ylim()

            for b in range(len(self.bg)):
                b_id = self.config['marked_task_states'][self.bg[b]]['id']
                b_color = self.config['marked_task_states'][self.bg[b]]['color']

                mask = np.where(LiveData['TaskStateNo']==b_id, 1, 0)
                if np.sum(mask) > 0:
                    self.plot_bg_mask(ax, i, range(self.xN), mask, [], b_color, 'none', None, 0.65)
                else:
                    # always draw patch for all colors so that they will always show up in the legend
                    z = self.zones[i]
                    patch = z[self.zone_idx[i]]
                    patch.set_xy([[0, 0],[0, 0],[0, 0],[0, 0]])
                    ax.draw_artist(patch)
                    self.zone_idx[i] = self.zone_idx[i] + 1


            # finger_threshold_judging_method: 1=distance, 2=absolute
            # finger threshold_judging_polarity: 1 = <, 2 = >
            methods = ~np.isnan(LiveData['JudgingMethod'][d])
            if np.sum(methods) > 0:
                methods = np.unique(LiveData['JudgingMethod'][d][methods])
                for m in range(len(methods)):
                    method = methods[m]
                    met_mask = np.where(LiveData['JudgingMethod'][d] == method, True, False)
                    polaritys = np.unique(LiveData['JudgingPolarity'][d][met_mask])

                    for p in range(len(polaritys)):
                        polarity = polaritys[p]
                        pol_mask = np.where(LiveData['JudgingPolarity'][d] == polarity, True, False)
                        mask = met_mask & pol_mask

                        yLimUs = np.unique(LiveData['ThreshUpper'][d][mask])

                        for b in range(len(yLimUs)):
                            yLimU = yLimUs[b]
                            submask = np.where(LiveData['ThreshUpper'][d] == yLimU, True, False) & mask

                            if method == 1: # dist
                                yLimLs = np.unique(LiveData['ThreshLower'][d][submask])

                                for k in range(len(yLimLs)):
                                    yLimL = yLimLs[k]
                                    submask2 = np.where(LiveData['ThreshLower'][d] == yLimL, True, False) & submask

                                    if polarity == 1:  # <
                                        self.plot_bg_mask(ax, i, range(self.xN), submask2, [yLimL, yLimU], 'none', 'black', '//', 1)
                                    else:
                                        self.plot_bg_mask(ax, i, range(self.xN), submask2, [yLimG[0], yLimL], 'none', 'black', '//', 1)
                                        self.plot_bg_mask(ax, i, range(self.xN), submask2, [yLimU, yLimG[1]], 'none', 'black', '//', 1)

                            else:           # abs
                                if polarity == 1: # <
                                    self.plot_bg_mask(ax, i, range(self.xN), submask, [yLimG[0], yLimU], 'none', 'black', '//', 1)
                                else:
                                    self.plot_bg_mask(ax, i, range(self.xN), submask, [yLimU, yLimG[1]], 'none', 'black', '//', 1)

            fail_mask = np.where(LiveData['TaskStateVerdict']==0, True, False)
            self.plot_bg_mask(ax, i, range(self.xN), fail_mask, [], 'red', 'none', None, 0.65)

            self.finger_pos[i].set_ydata(LiveData['ActualPos'][d])
            ax.draw_artist(self.finger_pos[i])

            self.blit(ax.bbox)

            if self.zone_idx[i] > 60:
                print "ERROR: too many zones! Increase number of preallocated patches"

        # need to redraw once to update y-ticks
        if self.redraw_yticks == True:
            self.draw() 
            self.redraw_yticks = False


    def pause(self, pause_state):
        self.paused = pause_state
        self.PausedData = copy.deepcopy(self.LiveData)


    def exit(self):
        print "exiting"
        self.parent.exit_app()


    def stop(self):
        print 'disconnecting'
        self.mod.SendSignal(rc.MT_EXIT_ACK)
        self.mod.DisconnectFromMMM()
Exemple #8
0
class MainFrame(BaseFrame):
    """Contains the main GUI and button boxes"""
    def __init__(self, parent, config, video, shuffle, Dataframe, savelabeled,
                 multianimal):
        super(MainFrame,
              self).__init__("DeepLabCut2.0 - Manual Outlier Frame Extraction",
                             parent)

        ###################################################################################################################################################
        # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting!
        # topSplitter = wx.SplitterWindow(self)
        #
        # self.image_panel = ImagePanel(topSplitter, config,video,shuffle,Dataframe,self.gui_size)
        # self.widget_panel = WidgetPanel(topSplitter)
        #
        # topSplitter.SplitHorizontally(self.image_panel, self.widget_panel,sashPosition=self.gui_size[1]*0.83)#0.9
        # topSplitter.SetSashGravity(1)
        # sizer = wx.BoxSizer(wx.VERTICAL)
        # sizer.Add(topSplitter, 1, wx.EXPAND)
        # self.SetSizer(sizer)

        # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting!

        topSplitter = wx.SplitterWindow(self)
        vSplitter = wx.SplitterWindow(topSplitter)

        self.image_panel = ImagePanel(vSplitter, config, self.gui_size)
        self.choice_panel = ScrollPanel(vSplitter)

        vSplitter.SplitVertically(self.image_panel,
                                  self.choice_panel,
                                  sashPosition=self.gui_size[0] * 0.8)
        vSplitter.SetSashGravity(1)
        self.widget_panel = WidgetPanel(topSplitter)
        topSplitter.SplitHorizontally(vSplitter,
                                      self.widget_panel,
                                      sashPosition=self.gui_size[1] *
                                      0.83)  # 0.9
        topSplitter.SetSashGravity(1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(topSplitter, 1, wx.EXPAND)
        self.SetSizer(sizer)

        ###################################################################################################################################################
        # Add Buttons to the WidgetPanel and bind them to their respective functions.

        widgetsizer = wx.WrapSizer(orient=wx.HORIZONTAL)

        self.load_button_sizer = wx.BoxSizer(wx.VERTICAL)
        self.help_button_sizer = wx.BoxSizer(wx.VERTICAL)

        self.help = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Help")
        self.help_button_sizer.Add(self.help, 1, wx.ALL, 15)
        #        widgetsizer.Add(self.help , 1, wx.ALL, 15)
        self.help.Bind(wx.EVT_BUTTON, self.helpButton)

        widgetsizer.Add(self.help_button_sizer, 1, wx.ALL, 0)

        self.grab = wx.Button(self.widget_panel,
                              id=wx.ID_ANY,
                              label="Grab Frames")
        widgetsizer.Add(self.grab, 1, wx.ALL, 15)
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.grab.Enable(True)

        widgetsizer.AddStretchSpacer(5)
        self.slider = wx.Slider(
            self.widget_panel,
            id=wx.ID_ANY,
            value=0,
            minValue=0,
            maxValue=1,
            size=(200, -1),
            style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS,
        )
        widgetsizer.Add(self.slider, 1, wx.ALL, 5)
        self.slider.Bind(wx.EVT_SLIDER, self.OnSliderScroll)

        widgetsizer.AddStretchSpacer(5)
        self.start_frames_sizer = wx.BoxSizer(wx.VERTICAL)
        self.end_frames_sizer = wx.BoxSizer(wx.VERTICAL)

        self.start_frames_sizer.AddSpacer(15)
        #        self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1), min=0, max=120)
        self.startFrame = wx.SpinCtrl(self.widget_panel,
                                      value="0",
                                      size=(100, -1))  # ,style=wx.SP_VERTICAL)
        self.startFrame.Enable(False)
        self.start_frames_sizer.Add(self.startFrame, 1,
                                    wx.EXPAND | wx.ALIGN_LEFT, 15)
        start_text = wx.StaticText(self.widget_panel,
                                   label="Start Frame Index")
        self.start_frames_sizer.Add(start_text, 1, wx.EXPAND | wx.ALIGN_LEFT,
                                    15)
        self.checkBox = wx.CheckBox(self.widget_panel,
                                    id=wx.ID_ANY,
                                    label="Range of frames")
        self.checkBox.Bind(wx.EVT_CHECKBOX, self.activate_frame_range)
        self.start_frames_sizer.Add(self.checkBox, 1,
                                    wx.EXPAND | wx.ALIGN_LEFT, 15)
        #
        self.end_frames_sizer.AddSpacer(15)
        self.endFrame = wx.SpinCtrl(self.widget_panel,
                                    value="1",
                                    size=(160, -1))  # , min=1, max=120)
        self.endFrame.Enable(False)
        self.end_frames_sizer.Add(self.endFrame, 1, wx.EXPAND | wx.ALIGN_LEFT,
                                  15)
        end_text = wx.StaticText(self.widget_panel, label="Number of Frames")
        self.end_frames_sizer.Add(end_text, 1, wx.EXPAND | wx.ALIGN_LEFT, 15)
        self.updateFrame = wx.Button(self.widget_panel,
                                     id=wx.ID_ANY,
                                     label="Update")
        self.end_frames_sizer.Add(self.updateFrame, 1,
                                  wx.EXPAND | wx.ALIGN_LEFT, 15)
        self.updateFrame.Bind(wx.EVT_BUTTON, self.updateSlider)
        self.updateFrame.Enable(False)

        widgetsizer.Add(self.start_frames_sizer, 1, wx.ALL, 0)
        widgetsizer.AddStretchSpacer(5)
        widgetsizer.Add(self.end_frames_sizer, 1, wx.ALL, 0)
        widgetsizer.AddStretchSpacer(15)

        self.quit = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Quit")
        widgetsizer.Add(self.quit, 1, wx.ALL, 15)
        self.quit.Bind(wx.EVT_BUTTON, self.quitButton)
        self.quit.Enable(True)

        self.widget_panel.SetSizer(widgetsizer)
        self.widget_panel.SetSizerAndFit(widgetsizer)

        # Variables initialization
        self.numberFrames = 0
        self.currFrame = 0
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.drs = []
        self.extract_range_frame = False
        self.firstFrame = 0
        self.Colorscheme = []

        # Read confing file
        self.cfg = auxiliaryfunctions.read_config(config)
        self.Task = self.cfg["Task"]
        self.start = self.cfg["start"]
        self.stop = self.cfg["stop"]
        self.date = self.cfg["date"]
        self.trainFraction = self.cfg["TrainingFraction"]
        self.trainFraction = self.trainFraction[0]
        self.videos = self.cfg["video_sets"].keys()
        self.bodyparts = self.cfg["bodyparts"]
        self.colormap = plt.get_cmap(self.cfg["colormap"])
        self.colormap = self.colormap.reversed()
        self.markerSize = self.cfg["dotsize"]
        self.alpha = self.cfg["alphavalue"]
        self.iterationindex = self.cfg["iteration"]
        self.cropping = self.cfg["cropping"]
        self.video_names = [Path(i).stem for i in self.videos]
        self.config_path = Path(config)
        self.video_source = Path(video).resolve()
        self.shuffle = shuffle
        self.Dataframe = Dataframe
        self.savelabeled = savelabeled
        self.multianimal = multianimal
        if self.multianimal:
            from deeplabcut.utils import auxfun_multianimal

            (
                self.individual_names,
                self.uniquebodyparts,
                self.multianimalbodyparts,
            ) = auxfun_multianimal.extractindividualsandbodyparts(self.cfg)
            self.choiceBox, self.visualization_rdb = self.choice_panel.addRadioButtons(
            )
            self.Colorscheme = visualization.get_cmap(
                len(self.individual_names), self.cfg["colormap"])
            self.visualization_rdb.Bind(wx.EVT_RADIOBOX, self.clear_plot)
        # Read the video file
        self.vid = VideoWriter(str(self.video_source))
        if self.cropping:
            self.vid.set_bbox(self.cfg["x1"], self.cfg["x2"], self.cfg["y1"],
                              self.cfg["y2"])
        self.filename = Path(self.video_source).name
        self.numberFrames = len(self.vid)
        self.strwidth = int(np.ceil(np.log10(self.numberFrames)))
        # Set the values of slider and range of frames
        self.startFrame.SetMax(self.numberFrames - 1)
        self.slider.SetMax(self.numberFrames - 1)
        self.endFrame.SetMax(self.numberFrames - 1)
        self.startFrame.Bind(wx.EVT_SPINCTRL, self.updateSlider)  # wx.EVT_SPIN
        # Set the status bar
        self.statusbar.SetStatusText("Working on video: {}".format(
            self.filename))
        # Adding the video file to the config file.
        if self.vid.name not in self.video_names:
            add.add_new_videos(self.config_path, [self.video_source])

        self.update()
        self.plot_labels()
        self.widget_panel.Layout()

    def quitButton(self, event):
        """
        Quits the GUI
        """
        self.statusbar.SetStatusText("")
        dlg = wx.MessageDialog(None, "Are you sure?", "Quit!",
                               wx.YES_NO | wx.ICON_WARNING)
        result = dlg.ShowModal()
        if result == wx.ID_YES:
            print("Quitting for now!")
            self.Destroy()

    def updateSlider(self, event):
        self.slider.SetValue(self.startFrame.GetValue())
        self.startFrame.SetValue(self.slider.GetValue())
        self.axes.clear()
        self.figure.delaxes(self.figure.axes[1])
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.currFrame = self.slider.GetValue()
        self.update()
        self.plot_labels()

    def activate_frame_range(self, event):
        """
        Activates the frame range boxes
        """
        self.checkSlider = event.GetEventObject()
        if self.checkSlider.GetValue():
            self.extract_range_frame = True
            self.startFrame.Enable(True)
            self.startFrame.SetValue(self.slider.GetValue())
            self.endFrame.Enable(True)
            self.updateFrame.Enable(True)
            self.grab.Enable(False)
        else:
            self.extract_range_frame = False
            self.startFrame.Enable(False)
            self.endFrame.Enable(False)
            self.updateFrame.Enable(False)
            self.grab.Enable(True)

    def line_select_callback(self, eclick, erelease):
        "eclick and erelease are the press and release events"
        self.new_x1, self.new_y1 = eclick.xdata, eclick.ydata
        self.new_x2, self.new_y2 = erelease.xdata, erelease.ydata

    def OnSliderScroll(self, event):
        """
        Slider to scroll through the video
        """
        self.axes.clear()
        self.figure.delaxes(self.figure.axes[1])
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.currFrame = self.slider.GetValue()
        self.startFrame.SetValue(self.currFrame)
        self.update()
        self.plot_labels()

    def update(self):
        """
        Updates the image with the current slider index
        """
        self.grab.Enable(True)
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.figure, self.axes, self.canvas = self.image_panel.getfigure()
        self.vid.set_to_frame(self.currFrame)
        frame = self.vid.read_frame(crop=self.cropping)
        if frame is not None:
            frame = img_as_ubyte(frame)
            self.ax = self.axes.imshow(frame, cmap=self.colormap)
            self.axes.set_title(
                str(
                    str(self.currFrame) + "/" + str(self.numberFrames - 1) +
                    " " + self.filename))
            self.figure.canvas.draw()
        else:
            print("Invalid frame")

    def chooseFrame(self):
        frame = img_as_ubyte(self.vid.read_frame(crop=self.cropping))
        fname = Path(self.filename)
        output_path = self.config_path.parents[0] / "labeled-data" / fname.stem

        self.machinefile = os.path.join(
            str(output_path),
            "machinelabels-iter" + str(self.iterationindex) + ".h5")
        name = str(fname.stem)
        DF = self.Dataframe.iloc[[self.currFrame]]
        DF.index = [
            os.path.join("labeled-data", name,
                         "img" + str(index).zfill(self.strwidth) + ".png")
            for index in DF.index
        ]
        img_name = (str(output_path) + "/img" + str(self.currFrame).zfill(
            int(np.ceil(np.log10(self.numberFrames)))) + ".png")
        labeled_img_name = (str(output_path) + "/img" + str(
            self.currFrame).zfill(int(np.ceil(np.log10(self.numberFrames)))) +
                            "labeled.png")

        # Check for it output path and a machine label file exist
        if output_path.exists() and Path(self.machinefile).is_file():
            io.imsave(img_name, frame)
            if self.savelabeled:
                self.figure.savefig(labeled_img_name, bbox_inches="tight")
            Data = pd.read_hdf(self.machinefile)
            DataCombined = pd.concat([Data, DF])
            DataCombined = DataCombined[~DataCombined.index.duplicated(
                keep="first")]
            DataCombined.to_hdf(self.machinefile,
                                key="df_with_missing",
                                mode="w")
            DataCombined.to_csv(
                os.path.join(str(output_path), "machinelabels.csv"))
        # If machine label file does not exist then create one
        elif output_path.exists() and not (Path(self.machinefile).is_file()):
            if self.savelabeled:
                self.figure.savefig(labeled_img_name, bbox_inches="tight")
            io.imsave(img_name, frame)
            #            cv2.imwrite(img_name, frame)
            DF.to_hdf(self.machinefile, key="df_with_missing", mode="w")
            DF.to_csv(os.path.join(str(output_path), "machinelabels.csv"))
        else:
            print(
                "%s path not found. Please make sure that the video was added to the config file using the function 'deeplabcut.add_new_videos'.Quitting for now!"
                % output_path)
            self.Destroy()

    def grabFrame(self, event):
        """
        Extracts the frame and saves in the current directory
        """

        if self.extract_range_frame:
            num_frames_extract = self.endFrame.GetValue()
            for i in range(self.currFrame,
                           self.currFrame + num_frames_extract):
                self.currFrame = i
                self.vid.set_to_frame(self.currFrame)
                self.chooseFrame()
        else:
            self.vid.set_to_frame(self.currFrame)
            self.chooseFrame()

    def clear_plot(self, event):
        self.figure.delaxes(self.figure.axes[1])
        [p.remove() for p in reversed(self.axes.patches)]
        self.plot_labels()

    def plot_labels(self):
        """
        Plots the labels of the analyzed video
        """
        self.vid.set_to_frame(self.currFrame)
        frame = self.vid.read_frame()
        if frame is not None:
            divider = make_axes_locatable(self.axes)
            cax = divider.append_axes("right", size="5%", pad=0.05)
            if self.multianimal:
                # take into account of all the bodyparts for the colorscheme. Sort the bodyparts to have same order as in the config file
                self.all_bodyparts = np.array(self.multianimalbodyparts +
                                              self.uniquebodyparts)
                _, return_idx = np.unique(self.all_bodyparts,
                                          return_index=True)
                self.all_bodyparts = list(
                    self.all_bodyparts[np.sort(return_idx)])

                if (self.visualization_rdb.GetSelection() == 0
                    ):  # i.e. for color scheme for individuals
                    self.Colorscheme = visualization.get_cmap(
                        len(self.individual_names), self.cfg["colormap"])
                    self.norm, self.colorIndex = self.image_panel.getColorIndices(
                        frame, self.individual_names)
                    cbar = self.figure.colorbar(self.ax,
                                                cax=cax,
                                                spacing="proportional",
                                                ticks=self.colorIndex)
                    cbar.set_ticklabels(self.individual_names)
                else:  # i.e. for color scheme for all bodyparts
                    self.Colorscheme = visualization.get_cmap(
                        len(self.all_bodyparts), self.cfg["colormap"])
                    self.norm, self.colorIndex = self.image_panel.getColorIndices(
                        frame, self.all_bodyparts)
                    cbar = self.figure.colorbar(self.ax,
                                                cax=cax,
                                                spacing="proportional",
                                                ticks=self.colorIndex)
                    cbar.set_ticklabels(self.all_bodyparts)

                for ci, ind in enumerate(self.individual_names):
                    col_idx = (
                        0
                    )  # variable for iterating through the colorscheme for all bodyparts
                    image_points = []
                    if ind == "single":
                        if self.visualization_rdb.GetSelection() == 0:
                            for c, bp in enumerate(self.uniquebodyparts):
                                pts = self.Dataframe.xs(
                                    (ind, bp),
                                    level=("individuals", "bodyparts"),
                                    axis=1,
                                ).values
                                self.circle = patches.Circle(
                                    pts[self.currFrame, :2],
                                    radius=self.markerSize,
                                    fc=self.Colorscheme(ci),
                                    alpha=self.alpha,
                                )
                                self.axes.add_patch(self.circle)
                        else:
                            for c, bp in enumerate(self.uniquebodyparts):
                                pts = self.Dataframe.xs(
                                    (ind, bp),
                                    level=("individuals", "bodyparts"),
                                    axis=1,
                                ).values
                                self.circle = patches.Circle(
                                    pts[self.currFrame, :2],
                                    radius=self.markerSize,
                                    fc=self.Colorscheme(col_idx),
                                    alpha=self.alpha,
                                )
                                self.axes.add_patch(self.circle)
                                col_idx = col_idx + 1
                    else:
                        if self.visualization_rdb.GetSelection() == 0:
                            for c, bp in enumerate(self.multianimalbodyparts):
                                pts = self.Dataframe.xs(
                                    (ind, bp),
                                    level=("individuals", "bodyparts"),
                                    axis=1,
                                ).values
                                self.circle = patches.Circle(
                                    pts[self.currFrame, :2],
                                    radius=self.markerSize,
                                    fc=self.Colorscheme(ci),
                                    alpha=self.alpha,
                                )
                                self.axes.add_patch(self.circle)
                        else:
                            for c, bp in enumerate(self.multianimalbodyparts):
                                pts = self.Dataframe.xs(
                                    (ind, bp),
                                    level=("individuals", "bodyparts"),
                                    axis=1,
                                ).values
                                self.circle = patches.Circle(
                                    pts[self.currFrame, :2],
                                    radius=self.markerSize,
                                    fc=self.Colorscheme(col_idx),
                                    alpha=self.alpha,
                                )
                                self.axes.add_patch(self.circle)
                                col_idx = col_idx + 1
                self.figure.canvas.draw()
            else:
                self.norm, self.colorIndex = self.image_panel.getColorIndices(
                    frame, self.bodyparts)
                cbar = self.figure.colorbar(self.ax,
                                            cax=cax,
                                            spacing="proportional",
                                            ticks=self.colorIndex)
                cbar.set_ticklabels(self.bodyparts)
                for bpindex, bp in enumerate(self.bodyparts):
                    color = self.colormap(self.norm(self.colorIndex[bpindex]))
                    self.points = [
                        self.Dataframe.xs((bp, "x"), level=(-2, -1),
                                          axis=1).values[self.currFrame],
                        self.Dataframe.xs((bp, "y"), level=(-2, -1),
                                          axis=1).values[self.currFrame],
                        1.0,
                    ]
                    circle = [
                        patches.Circle(
                            (self.points[0], self.points[1]),
                            radius=self.markerSize,
                            fc=color,
                            alpha=self.alpha,
                        )
                    ]
                    self.axes.add_patch(circle[0])
                self.figure.canvas.draw()
        else:
            print("Invalid frame")

    def helpButton(self, event):
        """
        Opens Instructions
        """
        wx.MessageBox(
            "1. Use the slider to select a frame in the entire video. \n\n2. Click Grab Frames button to save the specific frame.\
        \n\n3. In the events where you need to extract a range of frames, then use the checkbox 'Range of frames' to select the starting frame index and the number of frames to extract.\
        \n Click the update button to see the frame. Click Grab Frames to select the range of frames. \n\n Click OK to continue",
            "Instructions to use!",
            wx.OK | wx.ICON_INFORMATION,
        )
Exemple #9
0
class PlotPanel3DPopulation(wx.Panel):
	def __init__(self, parent):
		wx.Panel.__init__(self, parent)

		# Panel.
		panel_box = wx.BoxSizer(wx.VERTICAL)

		## Canvas.
		self.figure = Figure()
		self.canvas = Canvas(self, -1, self.figure)
		self.axes = None
		panel_box.Add(self.canvas, 1, wx.EXPAND)

		self.SetSizer(panel_box)

	def plot_data(self, bd, cm=jet, xlabel=None, ylabel=None, zlabel=None):
		"""
		Plot energy level populations by temperature in 3D.

		bd: BoltzmannDistribution.
		cm: A matplotlib colormap.
		*label: Axis labels.
		"""

		if self.axes is not None:
			self.figure.delaxes(self.axes)
			self.axes = None

		self.axes = self.figure.gca(projection='3d')

		# Set up the data.
		xs = self._gen_temps()
		ys = bd.energies
		verts = []

		# All the energy level populations at all the temperatures.
		populations = N.column_stack(bd.ps(x) for x in xs)

		for p in populations:
			# Add the points on the ends so that there is a bottom edge along
			# the polygon.
			points = [(xs[0], 0)] + list(zip(xs, p)) + [(xs[-1], 0)]
			verts.append(points)

		x_min, x_max = min(xs), max(xs)
		y_min, y_max = min(ys), max(ys)

		if y_max == y_min:
			colors = [cm(0.0) for i in bd.levels]
		else:
			colors = [cm((ys[i] - y_min) / (y_max - y_min)) for i in bd.levels]

		poly = PolyCollection(verts, facecolors=colors, linewidth=1.0, edgecolor='white')
		poly.set_alpha(0.7)

		# The directions here look somewhat confused, but that's just due to
		# the way the polygons are stacked.
		self.axes.add_collection3d(poly, zs=ys, zdir='y')

		if x_max == x_min:
			self.axes.set_xlim3d(x_min - 1, x_max + 1)
		else:
			self.axes.set_xlim3d(x_min, x_max)

		if y_max == y_min:
			self.axes.set_ylim3d(y_min - 1, y_max + 1)
		else:
			self.axes.set_ylim3d(y_min, y_max)

		self.axes.set_zlim3d(0, 1)

		if xlabel is not None:
			self.axes.set_xlabel(xlabel)

		if ylabel is not None:
			self.axes.set_ylabel(ylabel)

		if zlabel is not None:
			self.axes.set_zlabel(zlabel)

		self.figure.tight_layout()

		# Make sure that we redraw as the user drags.
		#
		# Using a list because we don't have nonlocal here.
		mouse_down = [False]

		def on_press(evt):
			mouse_down[0] = True

		def on_move(evt):
			if mouse_down[0]:
				self.canvas.draw()

		def on_release(evt):
			mouse_down[0] = False

		cid = self.canvas.mpl_connect('button_press_event', on_press)
		cid = self.canvas.mpl_connect('motion_notify_event', on_move)
		cid = self.canvas.mpl_connect('button_release_event', on_release)

	def _gen_temps(self):
		return N.linspace(0, 2000, 200)
Exemple #10
0
class App:
    def __init__(self,master):
        frame = Frame(master)
        frame.pack()
        
        self.wdir = os.getcwd() + '/'
        self.I = pp.Image()

        
        self.enstep = Entry(frame,width=5)
        self.enstep.pack(side=LEFT)
        self.enstep.insert(0, "0")

        
        self.varkeys = self.loaddata().get_varinfo(w_dir=self.wdir)['allvars']
        self.grid_dict= self.loaddata().grid(w_dir=self.wdir)
        

        self.ldatabutton=Button(frame,text="Load data",command=self.loaddata)
        self.ldatabutton.pack(side=LEFT)
        
        self.v = StringVar()
        self.v.set("rho")
        for variables in self.varkeys:
            self.ldata = Radiobutton(frame,text=variables,variable=self.v,value=variables,command=self.getmyvar)
            self.ldata.pack(side=LEFT)

        self.slvar = StringVar()
        self.slvar.set("Choose Slice")
        SliceList = ("Along x1","Along x2","Along x3","Along x1-x2","Along x2-x3","Along x3-x1")
        OptionMenu(frame, self.slvar, *SliceList, command=self.setslice).pack(side=LEFT)


        self.ex1 = Entry(frame,width=5)
        self.ex1.pack(side=LEFT)
        self.ex1.insert(0, "x1")

        self.ex2 = Entry(frame,width=5)
        self.ex2.pack(side=LEFT)
        self.ex2.insert(0, "x2")
        
        self.ex3 = Entry(frame,width=5)
        self.ex3.pack(side=LEFT)
        self.ex3.insert(0, "x3")

        self.xlb = Entry(frame,width=15)
        self.xlb.pack(side=LEFT)
        self.xlb.insert(0, "xlabel")

        self.ylb = Entry(frame,width=15)
        self.ylb.pack(side=LEFT)
        self.ylb.insert(0, "ylabel")
        

        

       

        self.logvar = IntVar()
        self.chkb = Checkbutton(frame,text="Enable Log",variable=self.logvar,onvalue=1,offvalue=0,command=self.logchkcall)
        self.chkb.pack(side=LEFT)

        self.polarvar = IntVar()
        self.polchkb = Checkbutton(frame,text="Polar",variable=self.polarvar,onvalue=1,offvalue=0,command=self.polchkcall)
        self.polchkb.pack(side=LEFT)

       # self.getplot= Button(frame,text='Plot',fg="black",command=self.plotfinal)
       # self.getplot.pack(side=LEFT)

        # place a graph somewhere here
        self.f = Figure(figsize=(8,8), dpi=100)
        self.a = self.f.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.f, master=root)
        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

        #self.toolbar = NavigationToolbar2TkAgg(self.canvas,frame)
        #self.toolbar.update()
        #self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)


    def loaddata(self):
        mynstep=int(self.enstep.get())
        self.D = pp.pload(mynstep,w_dir=self.wdir)
        return self.D

    def getmyvar(self):
       self.myvar=self.v.get()
        
    def logchkcall(self):
        self.logchk = self.logvar.get()

    def polchkcall(self):
        self.polchk = self.polarvar.get()
        
    def setslice(self,event):
        self.slicename=self.slvar.get()
        
    def plotclear(self):
        self.a.clear()
       
        
        if len(self.f.axes)>1:
            self.f.delaxes(self.f.axes[1])
            self.f.subplots_adjust(right=0.90)

        self.canvas.show()

    def plotfinal(self):
        if self.logvar.get() == 1:
            self.var = log10(self.D.__getattribute__(self.myvar))
        else:
            self.var = self.D.__getattribute__(self.myvar)

        if self.slicename == "Along x1":
            self.x = self.D.x1
            if self.grid_dict["n3"] == 1:
                self.var = self.var[:,int(self.ex2.get())]
            else:
                self.var = self.var[:,int(self.ex2.get()),int(self.ex3.get())]
            
        elif self.slicename == "Along x2":
            self.x = self.D.x2
            if self.grid_dict["n3"] == 1:
                self.var = self.var[int(self.ex1.get()),:]
            else:
                self.var = self.var[int(self.ex1.get()),:,int(self.ex3.get())]

        else:
            self.x = self.D.x3
            self.var = self.var[int(self.ex1.get()),int(self.ex2.get()),:]

        self.a.set_aspect('auto')
        self.a.plot(self.x,self.var)
        self.a.set_xlabel(self.xlb.get())
        self.a.set_ylabel(self.ylb.get())
        self.canvas.show()

    def plotsurface(self):
       
        if self.logvar.get() == 1:
            self.var = log10(self.D.__getattribute__(self.myvar))
        else:
            self.var = self.D.__getattribute__(self.myvar)
            
        if self.slicename == "Along x1-x2":
            self.x = self.D.x1
            self.y = self.D.x2
            if self.grid_dict["n3"] == 1:
                self.var = self.var[:,:].T
            else:
                if self.polarvar.get() == 1:
                    self.var = self.I.get_polar_plot(self.var[:,:,int(self.ex3.get())],rtheta=True)
                else:
                    self.var = self.var[:,:,int(self.ex3.get())].T
        

        elif self.slicename == "Along x2-x3":
            self.x = self.D.x2
            self.y = self.D.x3
            self.var = self.var[int(self.ex1.get()),:,:].T

        else:
            self.x = self.D.x1
            self.y = self.D.x3
            if self.polarvar.get() == 1:
                self.var = self.I.get_polar_plot(self.var[:,int(self.ex2.get()),:],rphi=True)
            else:
                self.var = self.var[:,int(self.ex2.get()),:].T

        
        self.a.set_aspect('equal')
        if self.polarvar.get() == 1:
           # if self.slicename == "Along x1-x2":self.a.axis([0,max(self.D.n1),0,max(self.D.n2)])
            #if self.slicename == "Along x3-x1":self.a.axis([0,max(self.D.n1),0,max(self.D.n3)])
            self.image=self.a.pcolormesh(self.var,vmin=min(self.var),vmax=max(self.var))
        else:
            self.a.axis([min(self.x),max(self.x),min(self.y),max(self.y)])
            self.image=self.a.pcolormesh(self.x,self.y,self.var,vmin=min(self.var),vmax=max(self.var))
        
        self.a.set_xlabel(self.xlb.get())
        self.a.set_ylabel(self.ylb.get())
        self.f.colorbar(self.image)
        self.canvas.show()
                         

        

    def epssave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.eps')
    def pngsave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.png')
    def pdfsave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.pdf')
    def jpgsave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.jpg')
Exemple #11
0
class Costmap2DFigure(FigureCanvas):
    costmap_changed = QtCore.Signal()
    
    """Implements an imshow figure for showing the costmap2d"""
    def __init__(self, costmap, parent=None, width=5.0, height=4.0, dpi=100, interpolation='nearest',
                    show_start = True, show_goal = True, show_colorbar = True):
        self.lock = Lock()
        self.costmap = costmap
        self.freeze = False
        self.interpolation = interpolation
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = self.fig.add_subplot(1,1,1)
        # We want the axes cleared every time plot() is called
        self.axes.hold(False)
        
        self.show_start = show_start
        self.start_coord = (-0.5, -0.5)
        self.start = Rectangle(self.start_coord, 1, 1, color='g')
        self.show_goal = show_goal
        self.goal_coord = (self.costmap.width-1.5, self.costmap.height-1.5)
        self.goal = Rectangle(self.goal_coord, 1, 1, color='k')
        self.show_colorbar = show_colorbar
        
        self.compute_initial_figure()
        
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)
        
        self.mpl_connect('button_release_event', self.on_mouse_release)
        
        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
        
        FigureCanvas.updateGeometry(self)
        
        self.on_mouse_click = self.default_on_mouse_click
        
        # Idle control
        self.idle = True
        
        # Make Qt Connections
        self.connect_stuff()
        
        # Override costmap on change
        self.costmap.on_update = self.costmap_update_callback
    
    def on_mouse_release(self, e):
        """Gets called when a mouse button is released"""
        if self.on_mouse_click != None:
            self.on_mouse_click(e)
    
    def default_on_mouse_click(self, e):
        """Default function for mouse clicking"""
        if e.xdata == None or e.ydata == None:
            return
        from math import floor
        coord = (floor(e.xdata+0.5)-0.5, floor(e.ydata+0.5)-0.5)
        if -0.5 > coord[0] < self.costmap.width-1.5 or \
           -0.5 > coord[1] < self.costmap.height-1.5:
            return
        if e.button == 1:
            self.start_coord = coord
            self.start = Rectangle(coord, 1, 1, color='g')
        elif e.button == 3:
            self.goal_coord = coord
            self.goal = Rectangle(coord, 1, 1, color='k')
        else:
            return
        self.on_map_update()
    
    def connect_stuff(self):
        """Make Qt connections"""
        self.costmap_changed.connect(self.on_map_update)
    
    def costmap_update_callback(self, key, val):
        """Callback to handle when the map is updated"""
        if self.idle:
            self.idle = False
            self.costmap_changed.emit()
    
    def compute_initial_figure(self):
        """Plot the imshow"""
        axes = self.axes.imshow(self.costmap.data.T, interpolation=self.interpolation)
        if self.show_colorbar: self.colorbar = self.fig.colorbar(axes)
        if self.show_start: self.axes.add_artist(self.start)
        if self.show_goal: self.axes.add_artist(self.goal)
    
    def on_map_update(self):
        """Slot to handle the costmap_changed signal"""
        if self.freeze: return
        self.lock.acquire()
        axes = self.axes.imshow(self.costmap.data.T, interpolation=self.interpolation)
        if self.show_colorbar:
            self.fig.delaxes(self.fig.axes[1])
            self.fig.subplots_adjust(right=0.90)
            self.colorbar = self.fig.colorbar(axes)
        if self.show_start: self.axes.add_artist(self.start)
        if self.show_goal: self.axes.add_artist(self.goal)
        self.draw()
        self.idle = True
        self.lock.release()
class Qt4MplCanvas(FigureCanvas):
    """  A customized Qt widget for matplotlib figure.
    It can be used to replace GraphicsView of QtGui
    """
    def __init__(self, parent):
        """  Initialization
        """
        # Instantiate matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')
        self.axes = self.fig.add_subplot(
            111)  # return: matplotlib.axes.AxesSubplot

        # Initialize parent class and set parent
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)

        # Variables to manage all lines/subplot
        self._lineDict = {}
        self._lineIndex = 0

        # legend and color bar
        self.colorBar = None
        # self._myLegend = None

        return

    def add_plot1d(self,
                   vec_x,
                   vec_y,
                   color=None,
                   label="",
                   x_label=None,
                   y_label=None,
                   marker=None,
                   line_style=None,
                   line_width=1,
                   y_err=None):
        """ Add a 1D plot (line) to canvas
        :param vec_x:
        :param vec_y:
        :param color:
        :param label:
        :param x_label:
        :param y_label:
        :param marker:
        :param line_style:
        :param line_width:
        :param y_err:
        :return:
        """
        # Check input
        if isinstance(vec_x, np.ndarray) is False or isinstance(
                vec_y, np.ndarray) is False:
            raise NotImplementedError(
                'Input vec_x or vec_y for addPlot() must be numpy.array.')
        plot_error = y_err is not None
        if plot_error is True:
            if isinstance(y_err, np.ndarray) is False:
                raise NotImplementedError(
                    'Input y_err must be either None or numpy.array.')

        if len(vec_x) != len(vec_y):
            raise NotImplementedError(
                'Input vec_x and vec_y must have same size.')
        if plot_error is True and len(y_err) != len(vec_x):
            raise NotImplementedError(
                'Input vec_x, vec_y and y_error must have same size.')

        # Hold previous data
        self.axes.hold(True)

        # process inputs and defaults
        # self.x = vec_x
        # self.y = vec_y

        if color is None:
            color = (0, 1, 0, 1)
        if marker is None:
            marker = 'o'
        if line_style is None:
            line_style = '-'

        # color must be RGBA (4-tuple)
        if plot_error is False:
            r = self.axes.plot(vec_x,
                               vec_y,
                               color=color,
                               marker=marker,
                               linestyle=line_style,
                               label=label,
                               linewidth=line_width)
            # return: list of matplotlib.lines.Line2D object
        else:
            r = self.axes.errorbar(vec_x,
                                   vec_y,
                                   yerr=y_err,
                                   color=color,
                                   marker=marker,
                                   linestyle=line_style,
                                   label=label,
                                   linewidth=line_width)

        self.axes.set_aspect('auto')

        # set x-axis and y-axis label
        if x_label is not None:
            self.axes.set_xlabel(x_label, fontsize=20)
        if y_label is not None:
            self.axes.set_ylabel(y_label, fontsize=20)

        # set/update legend
        self._setupLegend()

        # Register
        if plot_error is True and len(r) == 3:
            # plot line with error bar.  r[1] contains all lines
            self._lineDict[self._lineIndex] = r
        elif plot_error is False and len(r) == 1:
            # regular line
            self._lineDict[self._lineIndex] = r[0]
        else:
            print "Impoooooooooooooooosible! Number of returned tuple is %d" % (
                len(r))
            dbmsg = ''
            for sub_r in r:
                dbmsg += 'Type: %s, Value: %s\n' % (str(
                    type(sub_r)), str(sub_r))
            print dbmsg
        self._lineIndex += 1

        # Flush/commit
        self.draw()

        return

    def addPlot2D(self,
                  array2d,
                  xmin,
                  xmax,
                  ymin,
                  ymax,
                  holdprev,
                  yticklabels=None):
        """ Add a 2D plot

        Arguments:
         - yticklabels :: list of string for y ticks
        """
        # Release the current image
        self.axes.hold(holdprev)

        # Do plot
        # y ticks will be shown on line 1, 4, 23, 24 and 30
        # yticks = [1, 4, 23, 24, 30]
        # self.axes.set_yticks(yticks)

        print "[DBNOW] Before imshow(), number of axes = %d" % (len(
            self.fig.axes))

        # show image
        imgplot = self.axes.imshow(array2d,
                                   extent=[xmin, xmax, ymin, ymax],
                                   interpolation='none')
        print "[DBNOW] After imshow(), number of axes = %d" % (len(
            self.fig.axes))

        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            print "--------> [FixMe]: Set up the Y-axis ticks is erroreous"
            #self.axes.set_yticklabels(yticklabels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self.colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self.colorBar = self.fig.colorbar(imgplot)
        else:
            self.colorBar.update_bruteforce(imgplot)
        print "[DBNOW] After colorbar is added, number of axes = %d" % (len(
            self.fig.axes))

        # Flush...
        self._flush()

        return

    def addImage(self, imagefilename):
        """ Add an image by file
        """
        #import matplotlib.image as mpimg

        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img,
                                   extent=[0, 1000, 800, 0],
                                   interpolation='none',
                                   origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self.colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self.colorBar = self.fig.colorbar(imgplot)
        else:
            self.colorBar.update_bruteforce(imgplot)

        self._flush()

        return

    def clearAllLines(self):
        """ Remove all lines from the canvas
        """
        for ikey in self._lineDict.keys():
            plot = self._lineDict[ikey]
            if plot is None:
                continue
            if isinstance(plot, tuple) is False:
                try:
                    self.axes.lines.remove(plot)
                except ValueError as e:
                    print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
                        str(plot), len(self.axes.lines), str(e))
                self._lineDict[ikey] = None
            else:
                # error bar
                plot[0].remove()
                for line in plot[1]:
                    line.remove()
                for line in plot[2]:
                    line.remove()
                self._lineDict[ikey] = None
            # ENDIF(plot)
        # ENDFOR

        # Remove legend
        # only appied in new version of matplotlib
        # if self._myLegend is not None:
        #     self._myLegend.remove()

        self._setupLegend()

        self.draw()

        return

    def clearCanvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        self.axes.hold(False)

        # Clear all lines
        self.clearAllLines()

        # clear image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self.colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)
        if len(self.fig.axes) > 0:
            print "[DBNOW] Type of axes[0] = %s" % (str(type(
                self.fig.axes[0])))

        # flush/commit
        self._flush()

        return

    def getLastPlotIndexKey(self):
        """ Get the index/key of the last added line
        """
        return self._lineIndex - 1

    def getPlot(self):
        """ reture figure's axes to expose the matplotlib figure to PyQt client
        """
        return self.axes

    def getXLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_xlim()

    def getYLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_ylim()

    def setXYLimit(self, xmin, xmax, ymin, ymax):
        """
        """
        # for X
        xlims = self.axes.get_xlim()
        xlims = list(xlims)
        if xmin is not None:
            xlims[0] = xmin
        if xmax is not None:
            xlims[1] = xmax
        self.axes.set_xlim(xlims)

        # for Y
        ylims = self.axes.get_ylim()
        ylims = list(ylims)
        if ymin is not None:
            ylims[0] = ymin
        if ymax is not None:
            ylims[1] = ymax
        self.axes.set_ylim(ylims)

        # try draw
        self.draw()

        return

    def removePlot(self, ikey):
        """ Remove the line with its index as key
        """
        # self._lineDict[ikey].remove()
        lines = self.axes.lines
        print str(type(lines)), lines
        print "ikey = ", ikey, self._lineDict[ikey]
        self.axes.lines.remove(self._lineDict[ikey])
        #self.axes.remove(self._lineDict[ikey])
        print self._lineDict[ikey]
        self._lineDict[ikey] = None

        return

    def updateLine(self,
                   ikey,
                   vecx,
                   vecy,
                   linestyle=None,
                   linecolor=None,
                   marker=None,
                   markercolor=None):
        """
        """
        line = self._lineDict[ikey]

        if vecx is not None and vecy is not None:
            line.set_xdata(vecx)
            line.set_ydata(vecy)

        if linecolor is not None:
            line.set_color(linecolor)

        if linestyle is not None:
            line.set_linestyle(linestyle)

        if marker is not None:
            line.set_marker(marker)

        if markercolor is not None:
            line.set_markerfacecolor(markercolor)

        oldlabel = line.get_label()
        line.set_label(oldlabel)

        self.axes.legend()

        # commit
        self.draw()

        return

    def getLineStyleList(self):
        """
        """
        return MplLineStyles

    def getLineMarkerList(self):
        """
        """
        return MplLineMarkers

    def getLineBasicColorList(self):
        """
        """
        return MplBasicColors

    def getDefaultColorMarkerComboList(self):
        """ Get a list of line/marker color and marker style combination
        as default to add more and more line to plot
        """
        combolist = []
        nummarkers = len(MplLineMarkers)
        numcolors = len(MplBasicColors)

        for i in xrange(nummarkers):
            marker = MplLineMarkers[i]
            for j in xrange(numcolors):
                color = MplBasicColors[j]
                combolist.append((marker, color))
            # ENDFOR (j)
        # ENDFOR(i)

        return combolist

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w + 1, h)
        self.resize(w, h)

        return

    def _setupLegend(self, location='best'):
        """ Set up legend
        self.axes.legend()
        Handler is a Line2D object. Lable maps to the line object
        """
        loclist = [
            "best", "upper right", "upper left", "lower left", "lower right",
            "right", "center left", "center right", "lower center",
            "upper center", "center"
        ]

        # Check legend location valid or not
        if location not in loclist:
            location = 'best'

        handles, labels = self.axes.get_legend_handles_labels()
        # self._myLegend =
        self.axes.legend(handles, labels, loc=location)
        # print handles
        # print labels
        #self.axes.legend(self._myLegendHandlers, self._myLegentLabels)

        return
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 ) 
class MainFrame(wx.Frame):
    """Contains the main GUI and button boxes"""

    def __init__(self, parent,config,slider_width=25):
# Settting the GUI size and panels design
        displays = (wx.Display(i) for i in range(wx.Display.GetCount())) # Gets the number of displays
        screenSizes = [display.GetGeometry().GetSize() for display in displays] # Gets the size of each display
        index = 0 # For display 1.
        screenWidth = screenSizes[index][0]
        screenHeight = screenSizes[index][1]
        self.gui_size = (screenWidth*0.7,screenHeight*0.85)

        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = 'DeepLabCut2.0 - Manual Frame Extraction',
                            size = wx.Size(self.gui_size), pos = wx.DefaultPosition, style = wx.RESIZE_BORDER|wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetStatusText("")

        self.SetSizeHints(wx.Size(self.gui_size)) #  This sets the minimum size of the GUI. It can scale now!
        
###################################################################################################################################################
# Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting!
        topSplitter = wx.SplitterWindow(self)

        self.image_panel = ImagePanel(topSplitter, config,self.gui_size)
        self.widget_panel = WidgetPanel(topSplitter)
        
        topSplitter.SplitHorizontally(self.image_panel, self.widget_panel,sashPosition=self.gui_size[1]*0.83)#0.9
        topSplitter.SetSashGravity(1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(topSplitter, 1, wx.EXPAND)
        self.SetSizer(sizer)

###################################################################################################################################################
# Add Buttons to the WidgetPanel and bind them to their respective functions.

        widgetsizer = wx.WrapSizer(orient=wx.HORIZONTAL)

        self.load = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Load Video")
        widgetsizer.Add(self.load , 1, wx.ALL, 15)
        self.load.Bind(wx.EVT_BUTTON, self.browseDir)
        
        self.help = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Help")
        widgetsizer.Add(self.help , 1, wx.ALL, 15)
        self.help.Bind(wx.EVT_BUTTON, self.helpButton)

        self.grab = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Grab Frames")
        widgetsizer.Add(self.grab , 1, wx.ALL, 15)
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.grab.Enable(False)

        widgetsizer.AddStretchSpacer(5)
        size_x = round(self.gui_size[0] * (slider_width/100), 0)
        self.slider = wx.Slider(self.widget_panel, id=wx.ID_ANY, value = 0, minValue=0, maxValue=1,size=(size_x, -1), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS )
        widgetsizer.Add(self.slider,1, wx.ALL,5)
        self.slider.Hide()
        
        widgetsizer.AddStretchSpacer(5)
        self.start_frames_sizer = wx.BoxSizer(wx.VERTICAL)
        self.end_frames_sizer = wx.BoxSizer(wx.VERTICAL)

        self.start_frames_sizer.AddSpacer(15)
        self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1), min=0, max=120)
        self.startFrame.Bind(wx.EVT_SPINCTRL,self.updateSlider)
        self.startFrame.Enable(False)
        self.start_frames_sizer.Add(self.startFrame,1, wx.EXPAND|wx.ALIGN_LEFT,15)
        start_text = wx.StaticText(self.widget_panel, label='Start Frame Index')
        self.start_frames_sizer.Add(start_text,1, wx.EXPAND|wx.ALIGN_LEFT,15)
        self.checkBox = wx.CheckBox(self.widget_panel, id=wx.ID_ANY,label = 'Range of frames')
        self.checkBox.Bind(wx.EVT_CHECKBOX,self.activate_frame_range)
        self.start_frames_sizer.Add(self.checkBox,1, wx.EXPAND|wx.ALIGN_LEFT,15)
#        
        self.end_frames_sizer.AddSpacer(15)
        self.endFrame = wx.SpinCtrl(self.widget_panel, value='1', size=(160, -1), min=1, max=120)
        self.endFrame.Enable(False)
        self.end_frames_sizer.Add(self.endFrame,1, wx.EXPAND|wx.ALIGN_LEFT,15)
        end_text = wx.StaticText(self.widget_panel, label='Number of Frames')
        self.end_frames_sizer.Add(end_text,1, wx.EXPAND|wx.ALIGN_LEFT,15)
        self.updateFrame = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Update")
        self.end_frames_sizer.Add(self.updateFrame,1, wx.EXPAND|wx.ALIGN_LEFT,15)
        self.updateFrame.Bind(wx.EVT_BUTTON, self.updateSlider)
        self.updateFrame.Enable(False)
        
        widgetsizer.Add(self.start_frames_sizer,1,wx.ALL,0)
        widgetsizer.AddStretchSpacer(5)
        widgetsizer.Add(self.end_frames_sizer,1,wx.ALL,0)
        widgetsizer.AddStretchSpacer(15)
        
        self.quit = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Quit")
        widgetsizer.Add(self.quit , 1, wx.ALL, 15)
        self.quit.Bind(wx.EVT_BUTTON, self.quitButton)
        self.quit.Enable(True)

# Hiding these widgets and show them once the video is loaded
        self.start_frames_sizer.ShowItems(show=False)
        self.end_frames_sizer.ShowItems(show=False)

        self.widget_panel.SetSizer(widgetsizer)
        self.widget_panel.SetSizerAndFit(widgetsizer)
        self.widget_panel.Layout()
        
# Variables initialization
        self.numberFrames = 0
        self.currFrame = 0
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.drs = []
        self.cfg = auxiliaryfunctions.read_config(config)
        self.Task = self.cfg['Task']
        self.start = self.cfg['start']
        self.stop = self.cfg['stop']
        self.date = self.cfg['date']
        self.trainFraction = self.cfg['TrainingFraction']
        self.trainFraction = self.trainFraction[0]
        self.videos = self.cfg['video_sets'].keys()
        self.bodyparts = self.cfg['bodyparts']
        self.colormap = plt.get_cmap(self.cfg['colormap'])
        self.colormap = self.colormap.reversed()
        self.markerSize = self.cfg['dotsize']
        self.alpha = self.cfg['alphavalue']
        self.video_names = [Path(i).stem for i in self.videos]
        self.config_path = Path(config)
        self.extract_range_frame = False
        self.extract_from_analyse_video = False

    def quitButton(self, event):
        """
        Quits the GUI
        """
        self.statusbar.SetStatusText("")
        dlg = wx.MessageDialog(None,"Are you sure?", "Quit!",wx.YES_NO | wx.ICON_WARNING)
        result = dlg.ShowModal()
        if result == wx.ID_YES:
            print("Quitting for now!")
            self.Destroy()

    def updateSlider(self,event):
        self.slider.SetValue(self.startFrame.GetValue())
        self.currFrame = (self.slider.GetValue())
        if self.extract_from_analyse_video == True:
            self.figure.delaxes(self.figure.axes[1])
            self.plot_labels()
        self.update()
    
    def activate_frame_range(self,event):
        """
        Activates the frame range boxes
        """
        self.checkSlider = event.GetEventObject()
        if self.checkSlider.GetValue() == True:
            self.extract_range_frame = True
            self.startFrame.Enable(True)
            self.startFrame.SetValue(self.slider.GetValue())
            self.endFrame.Enable(True)
            self.updateFrame.Enable(True)
            self.grab.Enable(False)
        else:
            self.extract_range_frame = False
            self.startFrame.Enable(False)
            self.endFrame.Enable(False)
            self.updateFrame.Enable(False)
            self.grab.Enable(True)
    
    
    def line_select_callback(self,eclick, erelease):
        'eclick and erelease are the press and release events'
        self.new_x1, self.new_y1 = eclick.xdata, eclick.ydata
        self.new_x2, self.new_y2 = erelease.xdata, erelease.ydata

    
    
    def CheckCropping(self):
        ''' Display frame at time "time" for video to check if cropping is fine.
        Select ROI of interest by adjusting values in myconfig.py

        USAGE for cropping:
        clip.crop(x1=None, y1=None, x2=None, y2=None, width=None, height=None, x_center=None, y_center=None)

        Returns a new clip in which just a rectangular subregion of the
        original clip is conserved. x1,y1 indicates the top left corner and
        x2,y2 is the lower right corner of the cropped region.

        All coordinates are in pixels. Float numbers are accepted.
        '''

        videosource = self.video_source
        self.x1 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[0])
        self.x2 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[1])
        self.y1 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[2])
        self.y2 = int(self.cfg['video_sets'][videosource]['crop'].split(',')[3])

        if self.cropping==True:
# Select ROI of interest by drawing a rectangle
            self.cid = RectangleSelector(self.axes, self.line_select_callback,drawtype='box', useblit=False,button=[1], minspanx=5, minspany=5,spancoords='pixels',interactive=True)
            self.canvas.mpl_connect('key_press_event', self.cid)
            
    def OnSliderScroll(self, event):
        """
        Slider to scroll through the video
        """
        self.axes.clear()
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.currFrame = (self.slider.GetValue())
        self.startFrame.SetValue(self.currFrame)
        self.update()
    
    def is_crop_ok(self,event):
        """
        Checks if the cropping is ok
        """
        
        self.grab.SetLabel("Grab Frames")
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.slider.Show()
        self.start_frames_sizer.ShowItems(show=True)
        self.end_frames_sizer.ShowItems(show=True)
        self.widget_panel.Layout()
        self.slider.SetMax(self.numberFrames)
        self.startFrame.SetMax(self.numberFrames-1)
        self.endFrame.SetMax(self.numberFrames)
        self.x1 = int(self.new_x1)
        self.x2 = int(self.new_x2)
        self.y1 = int(self.new_y1)
        self.y2 = int(self.new_y2)
        self.canvas.mpl_disconnect(self.cid)
        self.axes.clear()
        self.currFrame = (self.slider.GetValue())
        self.update()
# Update the config.yaml file
        self.cfg['video_sets'][self.video_source] = {'crop': ', '.join(map(str, [self.x1, self.x2, self.y1, self.y2]))}
        auxiliaryfunctions.write_config(self.config_path,self.cfg)

        
    def browseDir(self, event):
        """
        Show the File Dialog and ask the user to select the video file
        """

        self.statusbar.SetStatusText("Looking for a video to start extraction..")
        dlg = wx.FileDialog(self, "SELECT A VIDEO", os.getcwd(), "", "*.*", wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.video_source_original = dlg.GetPath()
            self.video_source = str(Path(self.video_source_original).resolve())
            
            self.load.Enable(False)
        else:
            pass
            dlg.Destroy()
            self.Close(True)
        dlg.Destroy()
        selectedvideo = Path(self.video_source)
        
        self.statusbar.SetStatusText('Working on video: {}'.format(os.path.split(str(selectedvideo))[-1]))

        if  str(selectedvideo.stem) in self.video_names :
            self.grab.Enable(True)
            self.vid = cv2.VideoCapture(self.video_source)
            self.videoPath = os.path.dirname(self.video_source)
            self.filename = Path(self.video_source).name
            self.numberFrames = int(self.vid.get(cv2.CAP_PROP_FRAME_COUNT))
# Checks if the video is corrupt.
            if not self.vid.isOpened():
                msg = wx.MessageBox('Invalid Video file!Do you want to retry?', 'Error!', wx.YES_NO | wx.ICON_WARNING)
                if msg == 2:
                    self.load.Enable(True)
                    MainFrame.browseDir(self, event)
                else:
                    self.Destroy()
            self.slider.Bind(wx.EVT_SLIDER, self.OnSliderScroll)
            self.update()

            cropMsg = wx.MessageBox("Do you want to crop the frames?",'Want to crop?',wx.YES_NO|wx.ICON_INFORMATION)
            if cropMsg == 2:
                self.cropping = True
                self.grab.SetLabel("Set cropping parameters")
                self.grab.Bind(wx.EVT_BUTTON, self.is_crop_ok)
                self.widget_panel.Layout()
                self.basefolder = 'data-' + self.Task + '/'
                MainFrame.CheckCropping(self)
            else:
                self.cropping = False
                self.slider.Show()
                self.start_frames_sizer.ShowItems(show=True)
                self.end_frames_sizer.ShowItems(show=True)
                self.widget_panel.Layout()
                self.slider.SetMax(self.numberFrames-1)
                self.startFrame.SetMax(self.numberFrames-1)
                self.endFrame.SetMax(self.numberFrames-1)
       
        else:
            wx.MessageBox('Video file is not in config file. Use add function to add this video in the config file and retry!', 'Error!', wx.OK | wx.ICON_WARNING)
            self.Close(True)

    def update(self):
        """
        Updates the image with the current slider index
        """
        self.grab.Enable(True)
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.figure,self.axes,self.canvas = self.image_panel.getfigure()
        self.vid.set(1,self.currFrame)
        ret, frame = self.vid.read()
        if ret:
            frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        self.ax = self.axes.imshow(frame)
        self.axes.set_title(str(str(self.currFrame)+"/"+str(self.numberFrames-1) +" "+ self.filename))
        self.figure.canvas.draw()

    def chooseFrame(self):
        ret, frame = self.vid.read()
        fname = Path(self.filename)
        output_path = self.config_path.parents[0] / 'labeled-data' / fname.stem
        
        if output_path.exists() :
            frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame=img_as_ubyte(frame)
            img_name = str(output_path) +'/img'+str(self.currFrame).zfill(int(np.ceil(np.log10(self.numberFrames)))) + '.png'
            if self.cropping:
                crop_img = frame[self.y1:self.y2, self.x1:self.x2]
                cv2.imwrite(img_name, cv2.cvtColor(crop_img, cv2.COLOR_RGB2BGR))
            else:
                cv2.imwrite(img_name, cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
        else:
            print("%s path not found. Please make sure that the video was added to the config file using the function 'deeplabcut.add_new_videos'." %output_path)
    
    def grabFrame(self,event):
        """
        Extracts the frame and saves in the current directory
        """
        num_frames_extract = self.endFrame.GetValue()
        for i in range(self.currFrame,self.currFrame+num_frames_extract):
            self.currFrame = i
            self.vid.set(1,self.currFrame)
            self.chooseFrame()
        self.vid.set(1,self.currFrame)
        self.chooseFrame()

    def plot_labels(self):
        """
        Plots the labels of the analyzed video
        """
        self.vid.set(1,self.currFrame)
        ret, frame = self.vid.read()
        if ret:
            frame=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            self.norm = mcolors.Normalize(vmin=np.min(frame), vmax=np.max(frame))
            self.colorIndex = np.linspace(np.min(frame),np.max(frame),len(self.bodyparts))
            divider = make_axes_locatable(self.axes)
            cax = divider.append_axes("right", size="5%", pad=0.05)
            cbar = self.figure.colorbar(self.ax, cax=cax,spacing='proportional', ticks=self.colorIndex)
            cbar.set_ticklabels(self.bodyparts)
            for bpindex, bp in enumerate(self.bodyparts):
                color = self.colormap(self.norm(self.colorIndex[bpindex]))
                self.points = [self.Dataframe[self.scorer][bp]['x'].values[self.currFrame],self.Dataframe[self.scorer][bp]['y'].values[self.currFrame],1.0]
                circle = [patches.Circle((self.points[0], self.points[1]), radius=self.markerSize, fc = color , alpha=self.alpha)]
                self.axes.add_patch(circle[0])
            self.figure.canvas.draw()
        
    def helpButton(self,event):
        """
        Opens Instructions
        """
        wx.MessageBox('1. Use the Load Video button to load a video. Use the slider to select a frame in the entire video. The number mentioned on the top of the slider represents the frame index. \n\n2. Click Grab Frames button to save the specific frame.\n\n3. In events where you need to extract a range of frames, then use the checkbox Range of frames to select the start frame index and number of frames to extract. Click the update button to see the start frame index. Click Grab Frames to select the range of frames. \n\n Click OK to continue', 'Instructions to use!', wx.OK | wx.ICON_INFORMATION)
Exemple #15
0
class PlotPanel2DByTemperature(wx.Panel):
	DEFAULT_MIN_TEMP = 0
	DEFAULT_MAX_TEMP = 2000
	NUM_TEMPS = 200

	def __init__(self, parent, min_temp=None):
		wx.Panel.__init__(self, parent)

		self.min_temp = min_temp if min_temp is not None else self.DEFAULT_MIN_TEMP
		self.max_temp = self.DEFAULT_MAX_TEMP

		self.data_cache = None

		# Panel.
		panel_box = wx.BoxSizer(wx.VERTICAL)

		## Canvas.
		self.figure = Figure()
		self.canvas = Canvas(self, -1, self.figure)
		self.axes = None
		panel_box.Add(self.canvas, 1, wx.EXPAND)

		self.SetSizer(panel_box)

	def plot_data(self, fs, bds, xlabel=None, ylabel=None):
		self.data_cache = {
				'fs': fs,
				'bds': bds,
				'xlabel': xlabel,
				'ylabel': ylabel,
				}

		if self.axes is not None:
			self.figure.delaxes(self.axes)
			self.axes = None

		self.axes = self.figure.add_subplot(111)

		if xlabel is not None:
			self.axes.set_xlabel(xlabel)

		if ylabel is not None:
			self.axes.set_ylabel(ylabel)

		do_legend = False

		for f, bd in zip(fs, bds):
			label, color = bd.filename, bd.color

			if not do_legend and label is not None:
				do_legend = True

			xs = self._gen_temps()
			ys = [f(x) for x in xs]

			self.axes.plot(xs, ys, label=label, color=color)

		if do_legend:
			# Put the legend in the top-right corner, outside the axes.
			self.axes.legend(bbox_to_anchor=(0, 0, 1, 1), bbox_transform=self.figure.transFigure)

		self.figure.tight_layout()
		self.canvas.draw()

	def plot_cached_data(self):
		dc = self.data_cache

		if dc is None:
			return

		self.plot_data(dc['fs'], dc['bds'], xlabel=dc['xlabel'], ylabel=dc['ylabel'])

	def set_max_temp(self, temp):
		self.max_temp = temp

		self.plot_cached_data()

	def _gen_temps(self):
		return N.linspace(self.min_temp, self.max_temp, self.NUM_TEMPS)
class plothistogram(QFrame):
   def __init__(self, parent):
      print "__init__()"       # DEBUG
      QFrame.__init__(self)
      
      self.parent=parent
      #self.setModal(False)

      self.data1=self.parent.y1   # get plotted y values from solutions plot
      self.data2=self.parent.y2   # get plotted y values from parameter plot
      self.nbins=50               # default=50 bins
      self.parameter=self.parent.parent.parametersComboBox.currentText()
      self.data=self.parent.y2    # set histogram to solver parameter data

      #print "self.data = ", self.data   # DEBUG

      # Create canvas for plotting
      self.rim=0.1
      self.fig = Figure((5, 4), dpi=100)
      self.canvas = FigureCanvas(self.fig)
      self.canvas.setParent(self)
      self.fig.subplots_adjust(left=self.rim, right=1.0-self.rim, top=1.0-self.rim, bottom=self.rim)  # set a small rim

      self.mpl_toolbar = NavigationToolbar(self.canvas, self)
      self.mpl_toolbar.show()   # first hide the toolbar
      
      self.ax=self.fig.add_subplot(111)
      
      self.createWidgets()
      self.createLayout()
      self.connectSignals()
      self.setLabels()
      self.plot()
      
   def createWidgets(self):
      #print "createWidgets()"     # DEBUG
      
      self.closeButton=QPushButton("Close")
      self.closeButton.setToolTip("close this plotwindow")
      self.closeButton.show()

      self.histogramBinSpin=QSpinBox()            # spinbox for histogram binsize
      self.histogramBinSpin.setToolTip("Number of bins to histogram into")
      self.histogramBinSpin.setMinimum(5)
      #self.histogramBinSpin.setMaximum(150)        # set a maximum of 150 (reasonable?)
      self.histogramBinSpin.setSingleStep(10)       # allow only stepping by 10
      self.histogramBinSpin.setMaximumWidth(120)
      self.histogramBinSpin.setMinimumHeight(25)
      self.histogramBinSpin.setValue(self.nbins)
      self.histogramBinSpin.show()
      self.histogramBinLabel=QLabel("Bins")
      
      self.normedCheckBox=QCheckBox()
      self.normedCheckLabel=QLabel("Normalize")
      self.normedCheckBox.setToolTip("Normalize histogram")
      self.normedCheckBox.show()
      #self.dpi = 100
      
      self.dataComboBox=QComboBox()
      self.dataComboBox.addItem(self.parent.parent.parmValueComboBox.currentText())
      self.dataComboBox.addItem(self.parent.parent.parametersComboBox.currentText())
      self.dataComboBox.setMaximumWidth(120)
      self.dataComboBox.setMinimumHeight(25)
      self.dataComboBox.setCurrentIndex(1)

   def createLayout(self):
      #print "createLayout()"      # DEBUG
      
      self.normedLayout=QHBoxLayout()
      self.normedLayout.addWidget(self.normedCheckBox)
      self.normedLayout.addWidget(self.normedCheckLabel)
      self.buttonLayout=QVBoxLayout()
      self.plotLayout=QVBoxLayout()
      self.mainLayout=QHBoxLayout()
      self.buttonLayout.addLayout(self.normedLayout)
      #self.buttonLayout.addWidget(self.normedCheckBox)
      #self.buttonLayout.addWidget(self.normedCheckLabel)
      self.buttonLayout.addWidget(self.histogramBinSpin)
      self.buttonLayout.addWidget(self.dataComboBox)
      self.buttonLayout.insertStretch(-1)
      self.buttonLayout.addWidget(self.closeButton)
      self.plotLayout.addWidget(self.canvas)
      self.plotLayout.addWidget(self.mpl_toolbar)
      self.mainLayout.addLayout(self.buttonLayout)
      self.mainLayout.addLayout(self.plotLayout)
      
      self.setLayout(self.mainLayout)

   def setLabels(self):
      self.ax.xlabel="Bin"
      self.ax.ylabel="N"
      
   def setTitle(self):
      #=self.parent.parametersComboBox.currentText()
      #self.ax.xlabel=self.parmValueComboBox.currentText()
      #self.ax.xlabel="Bin No."
      #self.ax.ylabel="n"
      self.ax.title=self.parent.parent.parametersComboBox.currentText()
      
   def connectSignals(self):
      self.connect(self.closeButton, SIGNAL('clicked()'), SLOT('close()'))
      self.connect(self.histogramBinSpin, SIGNAL('valueChanged(int)'), self.on_changeBinSpin)      
      self.connect(self.normedCheckBox, SIGNAL('stateChanged(int)'), self.on_normedCheckBox)
      self.connect(self.dataComboBox, SIGNAL('currentIndexChanged(int)'), self.on_data)
      
   def on_changeBinSpin(self):
      self.nbins=self.histogramBinSpin.value()      
      # create histogram
      #n, bins = np.histogram(self.data, self.histogramBinSpin.value(), normed=self.normedCheckBox.isChecked())
      #hist, bins=np.histogram(self.data, self.nbins, normed=self.normedCheckBox.isChecked())
      
      #print "len(bins) = ", len(bins), " len(n) = ", len(n)
      
      #self.ax.plot(bins[1:], n, color='red')
      #self.canvas.draw()
      #self.ax.legend()
      #self.fig.draw_idle()        # redraw (preferably when idle)
      self.plot()

   def on_normedCheckBox(self):
      self.plot()

   def on_data(self):
      print "on_data()"       # DEBUG
      if self.dataComboBox.currentText()==self.parent.parent.parametersComboBox.currentText():
          self.data=self.data2
      else:
          self.data=self.data1
      self.plot()

   def plot(self):
      self.fig.delaxes(self.ax)            # delete all axes first
      self.ax=self.fig.add_subplot(111)
      
      n, bins = np.histogram(self.data, self.histogramBinSpin.value(), normed=self.normedCheckBox.isChecked())

      self.xmin=bins[1]
      self.xmax=bins[len(bins)-1]
      self.ax.bar(bins[1:], n, color='blue', width=(self.xmax-self.xmin)/len(bins))
      self.canvas.draw()
Exemple #17
0
class PlotContour(object):
    
    #===========================================================================
    def __init__(self,
                 orientation='vertical',
                 hover_target=None,
                 **kwargs):

        
        if orientation in ['v', 'vertical']:
            self.vertical_orientation = True
        else:
            self.vertical_orientation = False

        self.event_dict = {}
        self.targets = []

        self.hover_target = hover_target

        self.legend = None

        self.prop_fig = kwargs
        self._setup_figure()
        # self._add_event_hover()

    #===========================================================================
    def _setup_figure(self):
        self.fig = Figure(**self.prop_fig)
        self.ax = self.fig.add_subplot(111)

    # ===========================================================================
    def _add_event_hover(self):
        try:
            self.disconnect_event('motion_notify_event')
            self.disconnect_event('button_press_event')
        except:
            pass
        self.add_event('motion_notify_event', self._on_movement_hover)

    #===========================================================================
    def reset_plot(self):
        self.fig.delaxes(self.ax)

    #===========================================================================
    def add_target(self, target):
        if target not in self.targets:
            self.targets.append(target)

    def add_legend(self, **kwargs):
        self.legend = self.fig.legend(**kwargs)
        self.call_targets()

    #==========================================================================
    def add_event(self, event_type, event_function):
        if event_type in self.event_dict:
            print('Event already added')
            return
        self.event_dict[event_type] = {}
        self.event_dict[event_type]['event_type'] = event_type
        self.event_dict[event_type]['event_function'] = event_function
        self.event_dict[event_type]['object'] = self.fig.canvas.mpl_connect(event_type,
                                                                            event_function)

    #==========================================================================
    def disconnect_event(self, event_type):
        if event_type in self.event_dict:
            self.fig.canvas.mpl_disconnect(self.event_dict[event_type]['object'])
            self.event_dict.pop(event_type)

    #==========================================================================
    def disconnect_all_events(self):
        event_list = self.event_dict.keys()
        for event_type in event_list:
            self.disconnect_event(event_type)
    
    #===========================================================================
    def get_xlim(self):
        return self.ax.get_xlim()
            
    #===========================================================================
    def get_ylim(self):
        return self.ax.get_ylim()
        
    #===========================================================================
    def _on_click(self, event):
        pass

    def _on_movement_hover(self, event):
        self.hover_x = event.xdata
        self.hover_y = event.ydata
        self.call_target_hover()


    def call_target_hover(self):
        if self.hover_target:
            self.hover_target()
            
    #===========================================================================
    def call_targets(self):
        """
        Target is the mostly connected to updating a tk canvas.
        """
        if self.targets:
            for target in self.targets:
                target()
        else:
            self.fig.draw()
            self.fig.show()        

            
    #===========================================================================
    def set_x_grid(self, grid_on=True, sync_color_with_line_id='default'):
        self.ax.grid(grid_on, axis='x', linestyle=':')

        #===========================================================================
    def set_y_grid(self, grid_on=True, sync_color_with_line_id='default'):
        self.ax.grid(grid_on, axis='y', linestyle=':')

        #===========================================================================
    def zoom_to_data(self, call_targets=True):
        ax = self._get_ax_object(ax)
        if ax:
            ax.set_x_limits(call_targets=False)
            ax.set_y_limits(call_targets=False)
            if call_targets:
                self.call_range_targets()

    def _set_date_ticks(self):
        start_date, end_date = self.get_xlim()
        start_date = datetime.datetime.fromordinal(int(start_date))
        end_date = datetime.datetime.fromordinal(int(end_date))
        dt = end_date - start_date
        nr_days = dt.days

        if nr_days <= 30:
            loc = mdates.DayLocator()
            fmt = mdates.DateFormatter('%Y-%m-%d')
        elif nr_days <= 100:
            loc = mdates.DayLocator(bymonthday=[1, 15])
            fmt = mdates.DateFormatter('%Y-%m-%d')
        elif nr_days <= 365:
            loc = mdates.MonthLocator()
            fmt = mdates.DateFormatter('%Y-%m-%d')
        else:
            loc = mdates.MonthLocator(bymonthday=2)
            fmt = mdates.DateFormatter('%Y-%m-%d')

        self.ax.xaxis.set_major_locator(loc)
        self.ax.xaxis.set_major_formatter(fmt)

    #===========================================================================
    def set_x_limits(self, limits=[], call_targets=True):
        x_min, x_max = limits
        self.ax.set_xlim([x_min, x_max])

        # self._set_date_ticks()
        try:
            self._set_date_ticks()
        except:
            pass

        if call_targets:
            self.call_targets()
            
    #===========================================================================
    def set_y_limits(self, limits=[], call_targets=True):
        y_min, y_max = limits
        self.ax.set_xlim([y_min, y_max])

        if call_targets:
            self.call_targets()

            
    #===========================================================================
    def set_data(self, x=False, y=False, z=None, line_id='default', exclude_index=[], ax='first', call_targets=True, **kwargs):
        try:
            x = [pd.to_datetime(item) for item in x]
        except:
            pass

        X, Y = np.meshgrid(x, y)

        self.data = dict()
        self.data['x'] = x
        self.data['y'] = y
        self.data['X'] = X
        self.data['Y'] = Y
        self.data['Z'] = z


        self.ax.contourf(X, Y, z, kwargs.get('nr_levels', 50))

        if self.hover_target:
            self._add_event_hover()

        self.call_targets()

    #===========================================================================
    def set_label(self, label):
        if self.vertical_orientation:
            self.ax.set_y_label(label)
        else:
            self.ax.set_x_label(label)
Exemple #18
0
class SubWindow(QtGui.QWidget):
    "Base class for rasviewer document windows"

    cropChanged = QtCore.pyqtSignal()

    def __init__(self, ui_file, data_file, channel_file=None):
        super(SubWindow, self).__init__(None)
        self._load_interface(ui_file)
        try:
            self._load_data(data_file, channel_file)
        except (ValueError, IOError) as exc:
            QtGui.QMessageBox.critical(self, self.tr('Error'), str(exc))
            self.close()
            return
        self._config_interface()
        self._config_handlers()
        self.channel_changed()

    def _load_interface(self, ui_file):
        "Called by __init__ to load the Qt interface file"
        self.ui = None
        self.ui = uic.loadUi(get_ui_file(ui_file), self)

    def _load_data(self, data_file, channel_file=None):
        "Called by __init__ to load the data file"
        self._file = None
        self._progress = 0
        self._progress_update = None
        self._progress_dialog = None
        QtGui.QApplication.instance().setOverrideCursor(QtCore.Qt.WaitCursor)
        try:
            from rastools.data_parsers import DATA_PARSERS
        finally:
            QtGui.QApplication.instance().restoreOverrideCursor()
        # Open the selected file
        ext = os.path.splitext(data_file)[-1]
        parsers = dict(
            (ext, cls) for (cls, exts, _) in DATA_PARSERS for ext in exts)
        try:
            parser = parsers[ext]
        except KeyError:
            raise ValueError(
                self.tr('Unrecognized file extension "{0}"').format(ext))
        self._file = parser(data_file,
                            channel_file,
                            delay_load=False,
                            progress=(
                                self.progress_start,
                                self.progress_update,
                                self.progress_finish,
                            ))
        self.setWindowTitle(os.path.basename(data_file))

    def _config_interface(self):
        "Called by __init__ to configure the interface elements"
        self._info_dialog = None
        self._drag_start = None
        self._pan_id = None
        self._pan_crop = None
        self._zoom_id = None
        self._zoom_rect = None
        # Create a figure in a tab for the file
        self.figure = Figure(figsize=(5.0, 5.0),
                             dpi=FIGURE_DPI,
                             facecolor='w',
                             edgecolor='w')
        self.canvas = FigureCanvas(self.figure)
        self.image_axes = self.figure.add_axes((0.1, 0.1, 0.8, 0.8))
        self.histogram_axes = None
        self.colorbar_axes = None
        self.title_axes = None
        self.ui.splitter.addWidget(self.canvas)
        # Set up the redraw timer
        self.redraw_timer = QtCore.QTimer()
        self.redraw_timer.setInterval(REDRAW_TIMEOUT_DEFAULT)
        self.redraw_timer.timeout.connect(self.redraw_timeout)
        # Set up the limits of the crop spinners
        self.ui.crop_left_spinbox.setRange(0, self._file.x_size - 1)
        self.ui.crop_right_spinbox.setRange(0, self._file.x_size - 1)
        self.ui.crop_top_spinbox.setRange(0, self._file.y_size - 1)
        self.ui.crop_bottom_spinbox.setRange(0, self._file.y_size - 1)
        # Configure the common combos
        default = -1
        for interpolation in sorted(matplotlib.image.AxesImage._interpd):
            if interpolation == DEFAULT_INTERPOLATION:
                default = self.ui.interpolation_combo.count()
            self.ui.interpolation_combo.addItem(interpolation)
        self.ui.interpolation_combo.setCurrentIndex(default)
        if hasattr(self.ui, 'colorbar_check'):
            default = -1
            for color in sorted(matplotlib.cm.datad):
                if not color.endswith('_r'):
                    if color == DEFAULT_COLORMAP:
                        default = self.ui.colormap_combo.count()
                    self.ui.colormap_combo.addItem(color)
            self.ui.colormap_combo.setCurrentIndex(default)

    def _config_handlers(self):
        "Called by __init__ to connect events to handlers"
        # Set up common event connections
        self.ui.interpolation_combo.currentIndexChanged.connect(
            self.invalidate_image)
        self.ui.crop_top_spinbox.valueChanged.connect(self.crop_changed)
        self.ui.crop_left_spinbox.valueChanged.connect(self.crop_changed)
        self.ui.crop_right_spinbox.valueChanged.connect(self.crop_changed)
        self.ui.crop_bottom_spinbox.valueChanged.connect(self.crop_changed)
        self.ui.axes_check.toggled.connect(self.invalidate_image)
        self.ui.x_label_edit.textChanged.connect(self.invalidate_image)
        self.ui.y_label_edit.textChanged.connect(self.invalidate_image)
        self.ui.x_scale_spinbox.valueChanged.connect(self.x_scale_changed)
        self.ui.y_scale_spinbox.valueChanged.connect(self.y_scale_changed)
        self.ui.x_offset_spinbox.valueChanged.connect(self.x_offset_changed)
        self.ui.y_offset_spinbox.valueChanged.connect(self.y_offset_changed)
        self.ui.grid_check.toggled.connect(self.invalidate_image)
        self.ui.histogram_check.toggled.connect(self.invalidate_image)
        self.ui.histogram_bins_spinbox.valueChanged.connect(
            self.invalidate_image)
        self.ui.title_edit.textChanged.connect(self.invalidate_image)
        self.ui.default_title_button.clicked.connect(
            self.default_title_clicked)
        self.ui.clear_title_button.clicked.connect(self.clear_title_clicked)
        self.ui.title_info_button.clicked.connect(self.title_info_clicked)
        self.ui.splitter.splitterMoved.connect(self.splitter_moved)
        QtGui.QApplication.instance().focusChanged.connect(self.focus_changed)
        self.canvas.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.canvas.customContextMenuRequested.connect(self.canvas_popup)
        if hasattr(self.ui, 'colorbar_check'):
            self.ui.colorbar_check.toggled.connect(self.invalidate_image)
            self.ui.colormap_combo.currentIndexChanged.connect(
                self.invalidate_image)
            self.ui.reverse_check.toggled.connect(self.invalidate_image)
        self.press_id = self.canvas.mpl_connect('button_press_event',
                                                self.canvas_press)
        self.release_id = self.canvas.mpl_connect('button_release_event',
                                                  self.canvas_release)
        self.motion_id = self.canvas.mpl_connect('motion_notify_event',
                                                 self.canvas_motion)

    def splitter_moved(self, pos, index):
        self.invalidate_image()

    def progress_start(self):
        "Handler for loading progress start event"
        self._progress = 0
        self._progress_dialog = ProgressDialog(self.window())
        self._progress_dialog.show()
        self._progress_dialog.task = self.tr('Opening file')
        QtGui.QApplication.instance().setOverrideCursor(QtCore.Qt.WaitCursor)

    def progress_update(self, progress):
        "Handler for loading progress update event"
        now = time.time()
        if ((self._progress_update is None)
                or (now - self._progress_update) > 0.2):
            if self._progress_dialog.cancelled:
                raise KeyboardInterrupt
            self._progress_update = now
            if progress != self._progress:
                self._progress_dialog.progress = progress
                self._progress = progress

    def progress_finish(self):
        "Handler for loading progress finished event"
        QtGui.QApplication.instance().restoreOverrideCursor()
        if self._progress_dialog is not None:
            self._progress_dialog.close()
            self._progress_dialog = None

    def canvas_popup(self, pos):
        "Handler for canvas context menu event"
        menu = QtGui.QMenu(self)
        menu.addAction(self.window().ui.zoom_mode_action)
        menu.addAction(self.window().ui.pan_mode_action)
        menu.addSeparator()
        menu.addAction(self.window().ui.zoom_in_action)
        menu.addAction(self.window().ui.zoom_out_action)
        menu.addAction(self.window().ui.reset_zoom_action)
        menu.addSeparator()
        menu.addAction(self.window().ui.home_axes_action)
        menu.addAction(self.window().ui.reset_axes_action)
        menu.popup(self.canvas.mapToGlobal(pos))

    def canvas_motion(self, event):
        "Handler for mouse movement over graph canvas"
        raise NotImplementedError

    def canvas_press(self, event):
        "Handler for mouse press on graph canvas"
        if event.button != 1:
            return
        if event.inaxes != self.image_axes:
            return
        self._drag_start = Coord(event.x, event.y)
        if self.window().ui.zoom_mode_action.isChecked():
            self._zoom_id = self.canvas.mpl_connect('motion_notify_event',
                                                    self.canvas_zoom_motion)
        elif self.window().ui.pan_mode_action.isChecked():
            self._pan_id = self.canvas.mpl_connect('motion_notify_event',
                                                   self.canvas_pan_motion)
            self._pan_crop = Crop(top=self.ui.crop_top_spinbox.value(),
                                  left=self.ui.crop_left_spinbox.value(),
                                  bottom=self.ui.crop_bottom_spinbox.value(),
                                  right=self.ui.crop_right_spinbox.value())
            self.redraw_timer.setInterval(REDRAW_TIMEOUT_PAN)

    def canvas_pan_motion(self, event):
        "Handler for mouse movement in pan mode"
        inverse = self.image_axes.transData.inverted()
        start_x, start_y = inverse.transform_point(self._drag_start)
        end_x, end_y = inverse.transform_point((event.x, event.y))
        delta = Coord(int(start_x - end_x), int(start_y - end_y))
        if (self._pan_crop.left + delta.x >=
                0) and (self._pan_crop.right - delta.x >= 0):
            self.ui.crop_left_spinbox.setValue(self._pan_crop.left + delta.x)
            self.ui.crop_right_spinbox.setValue(self._pan_crop.right - delta.x)
        if (self._pan_crop.top + delta.y >=
                0) and (self._pan_crop.bottom - delta.y >= 0):
            self.ui.crop_top_spinbox.setValue(self._pan_crop.top + delta.y)
            self.ui.crop_bottom_spinbox.setValue(self._pan_crop.bottom -
                                                 delta.y)

    def canvas_zoom_motion(self, event):
        "Handler for mouse movement in zoom mode"
        # Calculate the display coordinates of the selection
        box_left, box_top, box_right, box_bottom = self.image_axes.bbox.extents
        height = self.figure.bbox.height
        band_left = max(min(self._drag_start.x, event.x), box_left)
        band_right = min(max(self._drag_start.x, event.x), box_right)
        band_top = max(min(self._drag_start.y, event.y), box_top)
        band_bottom = min(max(self._drag_start.y, event.y), box_bottom)
        rectangle = (band_left, height - band_top, band_right - band_left,
                     band_top - band_bottom)
        # Calculate the data coordinates of the selection. Note that top and
        # bottom are reversed by this conversion
        inverse = self.image_axes.transData.inverted()
        data_left, data_bottom = inverse.transform_point((band_left, band_top))
        data_right, data_top = inverse.transform_point(
            (band_right, band_bottom))
        # Ignore the drag operation until the total number of data-points in
        # the selection exceeds the threshold
        if (abs(data_right - data_left) *
                abs(data_bottom - data_top)) > ZOOM_THRESHOLD:
            self._zoom_rect = (data_left, data_top, data_right, data_bottom)
            self.window().statusBar().showMessage(
                self.tr('Crop from ({left:.0f}, {top:.0f}) to '
                        '({right:.0f}, {bottom:.0f})').format(
                            left=data_left,
                            top=data_top,
                            right=data_right,
                            bottom=data_bottom))
            self.canvas.drawRectangle(rectangle)
        else:
            self._zoom_rect = None
            self.window().statusBar().clearMessage()
            self.canvas.draw()

    def canvas_release(self, event):
        "Handler for mouse release on graph canvas"
        if self._pan_id:
            self.window().statusBar().clearMessage()
            self.canvas.mpl_disconnect(self._pan_id)
            self._pan_id = None
            self.redraw_timer.setInterval(REDRAW_TIMEOUT_DEFAULT)
        if self._zoom_id:
            self.window().statusBar().clearMessage()
            self.canvas.mpl_disconnect(self._zoom_id)
            self._zoom_id = None
            if self._zoom_rect:
                (
                    data_left,
                    data_top,
                    data_right,
                    data_bottom,
                ) = self._zoom_rect
                data_left = ((data_left / self.ui.x_scale_spinbox.value()) -
                             self.ui.x_offset_spinbox.value())
                data_right = ((data_right / self.ui.x_scale_spinbox.value()) -
                              self.ui.x_offset_spinbox.value())
                data_top = ((data_top / self.ui.y_scale_spinbox.value()) -
                            self.ui.y_offset_spinbox.value())
                data_bottom = (
                    (data_bottom / self.ui.y_scale_spinbox.value()) -
                    self.ui.y_offset_spinbox.value())
                self.ui.crop_left_spinbox.setValue(data_left)
                self.ui.crop_top_spinbox.setValue(data_top)
                self.ui.crop_right_spinbox.setValue(self._file.x_size -
                                                    data_right)
                self.ui.crop_bottom_spinbox.setValue(self._file.y_size -
                                                     data_bottom)
                self.canvas.draw()

    def channel_changed(self):
        "Handler for data channel change event"
        self.invalidate_data()
        self.crop_changed()

    def crop_changed(self, value=None):
        "Handler for crop_*_spinbox change event"
        self.cropChanged.emit()

    @property
    def zoom_factor(self):
        "Returns the percentage by which zoom in/out will operate"
        factor = 0.2
        height, width = self.data_cropped.shape[:2]
        return (max(1.0, width * factor), max(1.0, height * factor))

    @property
    def can_zoom_in(self):
        "Returns True if the image can be zoomed"
        height, width = self.data_cropped.shape[:2]
        x_factor, y_factor = self.zoom_factor
        return (width - x_factor * 2) * (height -
                                         y_factor * 2) > ZOOM_THRESHOLD

    @property
    def can_zoom_out(self):
        "Returns True if the image is zoomed"
        return (self.ui.crop_left_spinbox.value() > 0
                or self.ui.crop_right_spinbox.value() > 0
                or self.ui.crop_top_spinbox.value() > 0
                or self.ui.crop_bottom_spinbox.value())

    def zoom_in(self):
        "Zooms the image in by a fixed amount"
        x_factor, y_factor = self.zoom_factor
        self.ui.crop_left_spinbox.setValue(self.ui.crop_left_spinbox.value() +
                                           x_factor)
        self.ui.crop_right_spinbox.setValue(
            self.ui.crop_right_spinbox.value() + x_factor)
        self.ui.crop_top_spinbox.setValue(self.ui.crop_top_spinbox.value() +
                                          y_factor)
        self.ui.crop_bottom_spinbox.setValue(
            self.ui.crop_bottom_spinbox.value() + y_factor)

    def zoom_out(self):
        "Zooms the image out by a fixed amount"
        x_factor, y_factor = self.zoom_factor
        self.ui.crop_left_spinbox.setValue(
            max(0.0,
                self.ui.crop_left_spinbox.value() - x_factor))
        self.ui.crop_right_spinbox.setValue(
            max(0.0,
                self.ui.crop_right_spinbox.value() - x_factor))
        self.ui.crop_top_spinbox.setValue(
            max(0.0,
                self.ui.crop_top_spinbox.value() - y_factor))
        self.ui.crop_bottom_spinbox.setValue(
            max(0.0,
                self.ui.crop_bottom_spinbox.value() - y_factor))

    def reset_zoom(self):
        "Handler for reset_zoom_action triggered event"
        self.ui.crop_left_spinbox.setValue(0)
        self.ui.crop_right_spinbox.setValue(0)
        self.ui.crop_top_spinbox.setValue(0)
        self.ui.crop_bottom_spinbox.setValue(0)

    def reset_axes(self):
        "Handler for the reset_axes_action triggered event"
        self.ui.scale_locked_check.setChecked(True)
        self.ui.x_scale_spinbox.setValue(1.0)
        self.ui.y_scale_spinbox.setValue(1.0)
        self.ui.offset_locked_check.setChecked(True)
        self.ui.x_offset_spinbox.setValue(0.0)
        self.ui.y_offset_spinbox.setValue(0.0)

    def home_axes(self):
        "Handler for home_axes_action triggered event"
        self.ui.scale_locked_check.setChecked(True)
        self.ui.x_scale_spinbox.setValue(1.0)
        self.ui.y_scale_spinbox.setValue(1.0)
        self.ui.offset_locked_check.setChecked(False)
        self.ui.x_offset_spinbox.setValue(-self.ui.crop_left_spinbox.value())
        self.ui.y_offset_spinbox.setValue(-self.ui.crop_top_spinbox.value())

    def x_scale_changed(self, value):
        "Handler for x_scale_spinbox change event"
        if self.ui.scale_locked_check.isChecked():
            self.ui.y_scale_spinbox.setValue(value)
        self.invalidate_image()

    def y_scale_changed(self, value):
        "Handler for y_scale_spinbox change event"
        if self.ui.scale_locked_check.isChecked():
            self.ui.x_scale_spinbox.setValue(value)
        self.invalidate_image()

    def x_offset_changed(self, value):
        "Handler for x_offset_spinbox change event"
        if self.ui.offset_locked_check.isChecked():
            self.ui.y_offset_spinbox.setValue(value)
        self.invalidate_image()

    def y_offset_changed(self, value):
        "Handler for x_offset_spinbox change event"
        if self.ui.offset_locked_check.isChecked():
            self.ui.x_offset_spinbox.setValue(value)
        self.invalidate_image()

    def default_title_clicked(self):
        "Handler for default_title_button click event"
        raise NotImplementedError

    def clear_title_clicked(self):
        "Handler for clear_title_button click event"
        self.ui.title_edit.clear()

    def title_info_clicked(self, items):
        "Handler for title_info_button click event"
        from rastools.rasviewer.title_info_dialog import TitleInfoDialog
        if not self._info_dialog:
            self._info_dialog = TitleInfoDialog(self)
        self._info_dialog.ui.template_list.clear()
        for key, value in sorted(self.format_dict().items()):
            if isinstance(value, type('')):
                if '\n' in value:
                    value = value.splitlines()[0].rstrip()
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem(['{{{0}}}'.format(key), value]))
            elif isinstance(value, int):
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem(
                        ['{{{0}}}'.format(key), '{0}'.format(value)]))
                if 0 < value < 10:
                    self._info_dialog.ui.template_list.addTopLevelItem(
                        QtGui.QTreeWidgetItem([
                            '{{{0}:02d}}'.format(key), '{0:02d}'.format(value)
                        ]))
            elif isinstance(value, float):
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem(
                        ['{{{0}}}'.format(key), '{0}'.format(value)]))
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem(
                        ['{{{0}:.2f}}'.format(key), '{0:.2f}'.format(value)]))
            elif isinstance(value, dt.datetime):
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem(
                        ['{{{0}}}'.format(key), '{0}'.format(value)]))
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem([
                        '{{{0}:%Y-%m-%d}}'.format(key),
                        '{0:%Y-%m-%d}'.format(value)
                    ]))
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem([
                        '{{{0}:%H:%M:%S}}'.format(key),
                        '{0:%H:%M:%S}'.format(value)
                    ]))
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem([
                        '{{{0}:%A, %d %b %Y, %H:%M:%S}}'.format(key),
                        '{0:%A, %d %b %Y, %H:%M:%S}'.format(value)
                    ]))
            else:
                self._info_dialog.ui.template_list.addTopLevelItem(
                    QtGui.QTreeWidgetItem(
                        ['{{{0}}}'.format(key), '{0}'.format(value)]))
        self._info_dialog.show()

    @property
    def data(self):
        "Returns the original data array"
        raise NotImplementedError

    @property
    def data_cropped(self):
        "Returns the data after cropping"
        raise NotImplementedError

    @property
    def x_limits(self):
        "Returns a tuple of the X-axis limits after scaling and offset"
        if self.data_cropped is not None:
            return Range(
                (self.ui.x_scale_spinbox.value() or 1.0) *
                (self.ui.x_offset_spinbox.value() +
                 self.ui.crop_left_spinbox.value()),
                (self.ui.x_scale_spinbox.value() or 1.0) *
                (self.ui.x_offset_spinbox.value() + self._file.x_size -
                 self.ui.crop_right_spinbox.value()))

    @property
    def y_limits(self):
        "Returns a tuple of the Y-axis limits after scaling and offset"
        if self.data_cropped is not None:
            return Range(
                (self.ui.y_scale_spinbox.value() or 1.0) *
                (self.ui.y_offset_spinbox.value() + self._file.y_size -
                 self.ui.crop_bottom_spinbox.value()),
                (self.ui.y_scale_spinbox.value() or 1.0) *
                (self.ui.y_offset_spinbox.value() +
                 self.ui.crop_top_spinbox.value()))

    @property
    def axes_visible(self):
        "Returns True if the axes should be shown"
        return hasattr(self.ui,
                       'axes_check') and self.ui.axes_check.isChecked()

    @property
    def colorbar_visible(self):
        "Returns True if the colorbar should be shown"
        return hasattr(
            self.ui, 'colorbar_check') and self.ui.colorbar_check.isChecked()

    @property
    def histogram_visible(self):
        "Returns True if the histogram should be shown"
        return hasattr(
            self.ui,
            'histogram_check') and self.ui.histogram_check.isChecked()

    @property
    def margin_visible(self):
        "Returns True if the image margins should be shown"
        return (self.axes_visible or self.histogram_visible
                or self.colorbar_visible or bool(self.image_title))

    @property
    def x_margin(self):
        "Returns the size of the left and right margins when drawing"
        return 0.75 if self.margin_visible else 0.0

    @property
    def y_margin(self):
        "Returns the size of the top and bottom margins when drawing"
        return 0.25 if self.margin_visible else 0.0

    @property
    def sep_margin(self):
        "Returns the size of the separator between image elements"
        return 0.3

    @property
    def image_title(self):
        "Returns the text of the image title after substitution"
        result = ''
        try:
            if self.ui.title_edit.toPlainText():
                result = str(self.ui.title_edit.toPlainText()).format(
                    **self.format_dict())
        except KeyError as exc:
            self.ui.title_error_label.setText(
                'Unknown template "{}"'.format(exc))
            self.ui.title_error_label.show()
        except ValueError as exc:
            self.ui.title_error_label.setText(str(exc))
            self.ui.title_error_label.show()
        else:
            self.ui.title_error_label.hide()
        return result

    @property
    def figure_box(self):
        "Returns the overall bounding box"
        return BoundingBox(0.0, 0.0, self.figure.get_figwidth(),
                           self.figure.get_figheight())

    @property
    def colorbar_box(self):
        "Returns the colorbar bounding box"
        return BoundingBox(self.x_margin, self.y_margin,
                           self.figure_box.width - (self.x_margin * 2),
                           0.5 if self.colorbar_visible else 0.0)

    @property
    def title_box(self):
        "Returns the title bounding box"
        return BoundingBox(
            self.x_margin, self.figure_box.height -
            (self.y_margin + 1.0 if bool(self.image_title) else 0.0),
            self.figure_box.width - (self.x_margin * 2),
            1.0 if bool(self.image_title) else 0.0)

    @property
    def histogram_box(self):
        "Returns the histogram bounding box"
        return BoundingBox(
            self.x_margin, self.colorbar_box.top +
            (self.sep_margin if self.colorbar_visible else 0.0),
            self.figure_box.width - (self.x_margin * 2),
            (self.figure_box.height - (self.y_margin * 2) -
             self.colorbar_box.height - self.title_box.height -
             (self.sep_margin if self.colorbar_visible else 0.0) -
             (self.sep_margin if bool(self.image_title) else 0.0)) /
            2.0 if self.histogram_visible else 0.0)

    @property
    def image_box(self):
        "Returns the image bounding box"
        return BoundingBox(
            self.x_margin,
            self.histogram_box.top + (self.sep_margin if self.colorbar_visible
                                      or self.histogram_visible else 0.0),
            self.figure_box.width - (self.x_margin * 2),
            (self.figure_box.height -
             (self.y_margin * 2) - self.colorbar_box.height -
             self.title_box.height - self.histogram_box.height -
             (self.sep_margin if self.colorbar_visible else 0.0) -
             (self.sep_margin if self.histogram_visible else 0.0) -
             (self.sep_margin if bool(self.image_title) else 0.0)))

    def invalidate_image(self):
        "Invalidate the image"
        # Actually, this method doesn't immediately invalidate the image (as
        # this results in a horribly sluggish UI), but starts a timer which
        # causes a redraw after no invalidations have occurred for a period
        # (see __init__ for the duration)
        if self.redraw_timer.isActive():
            self.redraw_timer.stop()
        self.redraw_timer.start()

    def redraw_timeout(self):
        "Handler for the redraw_timer's timeout event"
        self.redraw_timer.stop()
        self.redraw_figure()

    def redraw_figure(self):
        "Called to redraw the channel image"
        # The following tests ensure we don't try and draw anything while we're
        # still loading the file
        if self._file and self.data is not None:
            # Draw the various image elements within bounding boxes calculated
            # from the metrics above
            image = self.draw_image()
            self.draw_histogram()
            self.draw_colorbar(image)
            self.draw_title()
            self.canvas.draw()

    def draw_image(self):
        "Draws the image of the data within the specified figure"
        raise NotImplementedError

    def draw_histogram(self):
        "Draws the data's historgram within the figure"
        raise NotImplementedError

    def draw_colorbar(self, image):
        "Draws a range color-bar within the figure"
        raise NotImplementedError

    def draw_title(self):
        "Draws a title within the specified figure"
        box = self.title_box.relative_to(self.figure_box)
        if bool(self.image_title):
            if self.title_axes is None:
                self.title_axes = self.figure.add_axes(box)
            else:
                self.title_axes.clear()
                self.title_axes.set_position(box)
            self.title_axes.set_axis_off()
            # Render the title
            self.title_axes.text(0.5,
                                 0,
                                 self.image_title,
                                 horizontalalignment='center',
                                 verticalalignment='baseline',
                                 multialignment='center',
                                 size='medium',
                                 family='sans-serif',
                                 transform=self.title_axes.transAxes)
        elif self.title_axes:
            self.figure.delaxes(self.title_axes)
            self.title_axes = None

    def format_dict(self):
        "Returns UI settings in a dict for use in format substitutions"
        raise NotImplementedError
Exemple #19
0
class Plot:
    """
    Plot class. Ultimately the aim is to pass this on to the GUI.
    """
    def __init__(self, data=None, backend=None):
        """
        Create a Plot object.
        Argument 'data' supplies a pandas.DataFrame with data to be plotted.
        Argument 'backend' is a str determining what backend the figure is for.
        This is passed on to matplotlib.use().
        (Perhaps 'Qt5Agg'?)
        Default is to plot with the console's backend, so as to enable easier
        interactive testing.
        """

        # Initialize some attributes.
        self.data = data
        if data is None:
            self.x = None
            self.y = None
        else:
            self.x = data.columns[0]
            self.y = data.columns[1]

        # Create the figure object that will be passed on,
        # depending on the requested mode.
        # Probably better not to determine the figure dimensions here,
        # but rather let the GUI alter them afterwards.
        if backend is None:
            self.fig = pyplot.figure()
            self.mode = 'console'
        else:
            matplotlib.use(backend)
            self.fig = Figure()
            self.mode = 'GUI'

        # Add the axes object to the figure.
        self.axes = self.fig.add_subplot(1, 1, 1)

    def clear(self):
        """
        Clear the axes of data, ready for a new plot.
        """

        self.fig.delaxes(self.axes)
        self.axes = self.fig.add_subplot(1, 1, 1)

    def get_figure(self):
        """
        Get the current plot and return it as a matplotlib Figure.
        """

        return self.fig

    def plot(self, x=None, y=None):
        """
        Draw the data onto the axes.
        Arguments 'x' and 'y' are str names of columns in data.
        Default is to plot the first two columns as x and y.
        Multiple calls to plot() will plot over existing data.
        Use clear() to clear the axes for a new plot.
        """

        # Use defaults if no input arguments.
        if x is None or y is None:
            x = self.x
            y = self.y

        # Draw.
        self.axes.plot(self.data[x], self.data[y])

    def set_data(self, data):
        """
        Change the data for the figure.
        Argument 'data' is a new pandas.DataFrame.
        """

        self.data = data
Exemple #20
0
class subplot(QtWidgets.QWidget):
    quickEditSignal = QtCore.Signal(object)
    rmSubplotSignal = QtCore.Signal(object)

    def __init__(self, context):
        super(subplot, self).__init__()
        self._context = context
        self.figure = Figure()
        self.figure.set_facecolor("none")
        self.canvas = FigureCanvas(self.figure)
        self._rm_window = None
        self._selector_window = None
        # update quick edit from tool bar
        self.canvas.mpl_connect("draw_event", self.draw_event_callback)

        self._ADSObserver = SubplotADSObserver(self)

        grid = QtWidgets.QGridLayout()
        # add toolbar
        self.toolbar = myToolbar(self.canvas, self)
        self.toolbar.update()
        grid.addWidget(self.toolbar, 0, 0)
        self.toolbar.setRmConnection(self._rm)
        self.toolbar.setRmSubplotConnection(self._rm_subplot)
        # add plot
        self.plotObjects = {}
        grid.addWidget(self.canvas, 1, 0)
        self.setLayout(grid)

    """ this is called when the zoom
    or pan are used. We want to send a
    signal to update the axis ranges """

    def draw_event_callback(self, event):
        self.figure.tight_layout()
        for subplot in self.plotObjects.keys():
            self.emit_subplot_range(subplot)

    def add_annotate(self, subplotName, label):
        if subplotName not in self._context.subplots.keys():
            return
        self._context.add_annotate(subplotName, label)
        self.canvas.draw()

    def add_vline(self, subplotName, xvalue, name, color):
        if subplotName not in self._context.subplots.keys():
            return
        self._context.add_vline(subplotName, xvalue, name, color)
        self.canvas.draw()

    def rm_annotate(self, subplotName, name):
        if subplotName not in self._context.subplots.keys():
            return
        self._context.removeLabel(subplotName, name)
        self.canvas.draw()

    def rm_vline(self, subplotName, name):
        if subplotName not in self._context.subplots.keys():
            return
        self._context.removeVLine(subplotName, name)
        self.canvas.draw()

    # plot a workspace, if a new subplot create it.
    def plot(self, subplotName, workspace, specNum=1):
        new = False
        if subplotName not in self._context.subplots.keys():
            self.add_subplot(subplotName, len(list(self.plotObjects.keys())))
            new = True
        self._add_plotted_line(subplotName, workspace, specNum=specNum)
        if new:
            self.emit_subplot_range(subplotName)

    def change_errors(self, state, subplotNames):
        for subplotName in subplotNames:
            self._context.subplots[subplotName].change_errors(state)
            self.canvas.draw()

    # adds plotted line to context and updates GUI
    def _add_plotted_line(self, subplotName, workspace, specNum):
        """ Appends plotted lines to the related subplot list. """
        self._context.addLine(subplotName, workspace, specNum)
        self.canvas.draw()

    def add_subplot(self, subplotName, number):
        self._context.update_gridspec(number + 1)
        gridspec = self._context.gridspec
        self.plotObjects[subplotName] = self.figure.add_subplot(
            gridspec[number], label=subplotName, projection='mantid')
        self.plotObjects[subplotName].set_title(subplotName)
        self._context.addSubplot(subplotName, self.plotObjects[subplotName])
        self._update()

    def _update(self):
        self._context.update_layout(self.figure)
        self.canvas.draw()

    def emit_subplot_range(self, subplotName):
        self.quickEditSignal.emit(subplotName)
        self._context.subplots[subplotName].redraw_annotations()

    def set_plot_x_range(self, subplotNames, range):
        for subplotName in subplotNames:
            # make a set method in context and set it there
            self.plotObjects[subplotName].set_xlim(range)
            self._context.subplots[subplotName].redraw_annotations()
            self.canvas.draw()

    def set_plot_y_range(self, subplotNames, y_range):
        for subplotName in subplotNames:
            self.plotObjects[subplotName].set_ylim(y_range)
            self._context.subplots[subplotName].redraw_annotations()
            self.canvas.draw()

    def connect_quick_edit_signal(self, slot):
        self.quickEditSignal.connect(slot)

    def disconnect_quick_edit_signal(self):
        self.quickEditSignal.disconnect()

    def connect_rm_subplot_signal(self, slot):
        self.rmSubplotSignal.connect(slot)

    def disconnect_rm_subplot_signal(self):
        self.rmSubplotSignal.disconnect()

    def set_y_autoscale(self, subplotNames, state):
        for subplotName in subplotNames:
            self._context.subplots[subplotName].change_auto(state)
            self.canvas.draw()

    def _rm(self):
        names = list(self._context.subplots.keys())
        if len(names) == 1:
            if self._rm_window is not None:
                self._rm_window.show()
            else:
                self._get_rm_window(names[0])
        else:
            if self._rm_window is not None:
                self._rm_window.close()
                self._rm_window = None
            self._close_selector_window()

            self._selector_window = self._createSelectWindow(names)
            self._selector_window.subplotSelectorSignal.connect(self._get_rm_window)
            self._selector_window.closeEventSignal.connect(self._close_selector_window)
            self._selector_window.setMinimumSize(300, 100)
            self._selector_window.show()

    def _rm_subplot(self):
        names = list(self._context.subplots.keys())
        # If the selector is hidden then close it
        self._close_selector_window()

        self._selector_window = self._createSelectWindow(names)
        self._selector_window.subplotSelectorSignal.connect(self._remove_subplot)
        self._selector_window.subplotSelectorSignal.connect(self._close_selector_window)
        self._selector_window.closeEventSignal.connect(self._close_selector_window)
        self._selector_window.setMinimumSize(300, 100)
        self._selector_window.show()

    def _createSelectWindow(self, names):
        return SelectSubplot(names)

    def _close_selector_window(self):
        if self._selector_window is not None:
            self._selector_window.close()
            self._selector_window = None

    def _create_rm_window(self, subplotName):
        line_names = list(self._context.subplots[subplotName].lines.keys())
        vline_names = self._context.subplots[subplotName].vlines
        return RemovePlotWindow(lines=line_names, vlines=vline_names, subplot=subplotName, parent=self)

    def _get_rm_window(self, subplotName):
        # always close selector after making a selection
        self._close_selector_window()
        # create the remove window
        self._rm_window = self._create_rm_window(subplotName=subplotName)
        self._rm_window.applyRemoveSignal.connect(self._applyRm)
        self._rm_window.closeEventSignal.connect(self._close_rm_window)
        self._rm_window.setMinimumSize(200, 200)
        self._rm_window.show()

    def _applyRm(self, names):
        remove_subplot = True
        # remove the lines from the subplot
        for name in names:
            if self._rm_window.getState(name):
                self._context.subplots[
                    self._rm_window.subplot].removeLine(name)
            else:
                remove_subplot = False
        # if all of the lines have been removed -> delete subplot
        if remove_subplot:
            self._remove_subplot(self._rm_window.subplot)
        else:
            self.canvas.draw()
        # if no subplots then close plotting window
        if len(self._context.subplots.keys()) == 0:
            self._close_rm_window()
            # close plot window once auto grid done
        else:
            self._close_rm_window()

    def _close_rm_window(self):
        self._rm_window.close
        self._rm_window = None

    def _remove_subplot(self, subplotName):
        self.figure.delaxes(self.plotObjects[subplotName])
        del self.plotObjects[subplotName]
        self._context.delete(subplotName)
        self._context.update_gridspec(len(list(self.plotObjects.keys())))
        self._update()
        self.rmSubplotSignal.emit(subplotName)

    def _rm_ws_from_plots(self, workspace_name):
        keys = deepcopy(self._context.subplots.keys())
        for subplot in keys:
            labels = self._context.get_lines_from_WS(subplot, workspace_name)
            for label in labels:
                self._context.removePlotLine(subplot, label)
                self.canvas.draw()
            if self._context.is_subplot_empty(subplot):
                self._remove_subplot(subplot)

    def _replaced_ws(self, workspace):
        for subplot in self._context.subplots.keys():
            redraw = self._context.subplots[subplot].replace_ws(workspace)
            if redraw:
                self.canvas.draw()
Exemple #21
0
class PlotPanel(wx.Panel):
    def __init__(self, parent, selPanel,infoPanel=None, mainframe=None):

        # Superclass constructor
        super(PlotPanel,self).__init__(parent)

        # Font handling
        font = parent.GetFont()
        font.SetPointSize(font.GetPointSize()-1)
        self.SetFont(font) 
        # Preparing a special font manager for chinese characters
        self.specialFont=None
        CH_F_PATHS = [
                os.path.join(pyplot_rc['datapath'], 'fonts/ttf/SimHei.ttf'),
                os.path.join(os.path.dirname(__file__),'../SimHei.ttf')]
        for fpath in CH_F_PATHS:
            if os.path.exists(fpath):
                fontP = font_manager.FontProperties(fname=fpath)
                fontP.set_size(font.GetPointSize())
                self.specialFont=fontP
                break
        # data
        self.selPanel = selPanel
        self.infoPanel=infoPanel
        self.parent   = parent
        self.mainframe= mainframe
        self.plotData = []
        if self.selPanel is not None:
            bg=self.selPanel.BackgroundColour
            self.SetBackgroundColour(bg) # sowhow, our parent has a wrong color
        # GUI
        self.fig = Figure(facecolor="white", figsize=(1, 1))
        self.fig.set_tight_layout(True) # subplots_adjust(top=0.98,bottom=0.12,left=0.12,right=0.98)
        self.canvas = FigureCanvas(self, -1, self.fig)
        self.canvas.mpl_connect('motion_notify_event', self.onMouseMove)

        self.navTB = MyNavigationToolbar2Wx(self.canvas)


        # --- Tool Panel
        self.toolSizer= wx.BoxSizer(wx.VERTICAL)
        # --- PlotType Panel
        self.pltTypePanel= PlotTypePanel(self);
        # --- Plot type specific options
        self.spcPanel = SpectralCtrlPanel(self)
        self.pdfPanel = PDFCtrlPanel(self)
        self.cmpPanel = CompCtrlPanel(self)
        self.mmxPanel = MinMaxPanel(self)

        # --- Ctrl Panel
        self.ctrlPanel= wx.Panel(self)
        # Check Boxes
        self.cbScatter = wx.CheckBox(self.ctrlPanel, -1, 'Scatter',(10,10))
        self.cbSub     = wx.CheckBox(self.ctrlPanel, -1, 'Subplot',(10,10))
        self.cbLogX    = wx.CheckBox(self.ctrlPanel, -1, 'Log-x',(10,10))
        self.cbLogY    = wx.CheckBox(self.ctrlPanel, -1, 'Log-y',(10,10))
        self.cbSync    = wx.CheckBox(self.ctrlPanel, -1, 'Sync-x',(10,10))
        self.cbXHair   = wx.CheckBox(self.ctrlPanel, -1, 'CrossHair',(10,10))
        #self.cbSub.SetValue(True) # DEFAULT TO SUB?
        self.cbSync.SetValue(True)
        self.cbXHair.SetValue(True) # Have cross hair by default
        self.Bind(wx.EVT_CHECKBOX, self.scatter_select, self.cbScatter)
        self.Bind(wx.EVT_CHECKBOX, self.redraw_event  , self.cbSub    )
        self.Bind(wx.EVT_CHECKBOX, self.log_select    , self.cbLogX   )
        self.Bind(wx.EVT_CHECKBOX, self.log_select    , self.cbLogY   )
        self.Bind(wx.EVT_CHECKBOX, self.redraw_event  , self.cbSync )
        self.Bind(wx.EVT_CHECKBOX, self.crosshair_event, self.cbXHair )
        # LAYOUT
        cb_sizer  = wx.FlexGridSizer(rows=3, cols=2, hgap=2, vgap=0)
        cb_sizer.Add(self.cbScatter, 0, flag=wx.ALL, border=1)
        cb_sizer.Add(self.cbSub    , 0, flag=wx.ALL, border=1)
        cb_sizer.Add(self.cbLogX   , 0, flag=wx.ALL, border=1)
        cb_sizer.Add(self.cbLogY   , 0, flag=wx.ALL, border=1)
        cb_sizer.Add(self.cbSync   , 0, flag=wx.ALL, border=1)
        cb_sizer.Add(self.cbXHair  , 0, flag=wx.ALL, border=1)
        self.ctrlPanel.SetSizer(cb_sizer)
        # --- Ctrl Panel
        crossHairPanel= wx.Panel(self)
        self.lbCrossHairX = wx.StaticText(crossHairPanel, -1, 'x= ...      ')
        self.lbCrossHairY = wx.StaticText(crossHairPanel, -1, 'y= ...      ')
        self.lbCrossHairX.SetFont(getMonoFont(self))
        self.lbCrossHairY.SetFont(getMonoFont(self))
        cbCH  = wx.FlexGridSizer(rows=2, cols=1, hgap=2, vgap=0)
        cbCH.Add(self.lbCrossHairX   , 0, flag=wx.ALL, border=1)
        cbCH.Add(self.lbCrossHairY   , 0, flag=wx.ALL, border=1)
        crossHairPanel.SetSizer(cbCH)


        # --- layout of panels
        row_sizer = wx.BoxSizer(wx.HORIZONTAL)
        sl2 = wx.StaticLine(self, -1, size=wx.Size(1,-1), style=wx.LI_VERTICAL)
        sl3 = wx.StaticLine(self, -1, size=wx.Size(1,-1), style=wx.LI_VERTICAL)
        sl4 = wx.StaticLine(self, -1, size=wx.Size(1,-1), style=wx.LI_VERTICAL)
        row_sizer.Add(self.pltTypePanel , 0 , flag=wx.ALL|wx.CENTER           , border=2)
        row_sizer.Add(sl2               , 0 , flag=wx.EXPAND|wx.CENTER        , border=0)
        row_sizer.Add(self.navTB        , 0 , flag=wx.LEFT|wx.RIGHT|wx.CENTER , border=2)
        row_sizer.Add(sl3               , 0 , flag=wx.EXPAND|wx.CENTER        , border=0)
        row_sizer.Add(self.ctrlPanel    , 1 , flag=wx.ALL|wx.EXPAND|wx.CENTER , border=2)
        row_sizer.Add(sl4               , 0 , flag=wx.EXPAND|wx.CENTER        , border=0)
        row_sizer.Add(crossHairPanel,0, flag=wx.EXPAND|wx.CENTER|wx.LEFT    , border=2)

        plotsizer = wx.BoxSizer(wx.VERTICAL)
        self.slCtrl = wx.StaticLine(self, -1, size=wx.Size(-1,1), style=wx.LI_HORIZONTAL)
        self.slCtrl.Hide()
        sl1 = wx.StaticLine(self, -1, size=wx.Size(-1,1), style=wx.LI_HORIZONTAL)
        plotsizer.Add(self.toolSizer,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10)
        plotsizer.Add(self.canvas   ,1,flag = wx.EXPAND,border = 5 )
        plotsizer.Add(sl1           ,0,flag = wx.EXPAND,border = 0)
        plotsizer.Add(self.spcPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10)
        plotsizer.Add(self.pdfPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10)
        plotsizer.Add(self.cmpPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10)
        plotsizer.Add(self.mmxPanel ,0,flag = wx.EXPAND|wx.CENTER|wx.TOP|wx.BOTTOM,border = 10)
        plotsizer.Add(self.slCtrl   ,0,flag = wx.EXPAND,border = 0)
        plotsizer.Add(row_sizer     ,0,flag = wx.NORTH ,border = 5)

        self.show_hide(self.spcPanel, self.pltTypePanel.cbFFT.GetValue())
        self.show_hide(self.cmpPanel, self.pltTypePanel.cbCompare.GetValue())
        self.show_hide(self.pdfPanel, self.pltTypePanel.cbPDF.GetValue())
        self.show_hide(self.mmxPanel, self.pltTypePanel.cbMinMax.GetValue())

        self.SetSizer(plotsizer)
        self.plotsizer=plotsizer;

    def redraw_event(self, event):
        self.redraw_same_data()

    def log_select(self, event):
        if self.pltTypePanel.cbPDF.GetValue():
            self.cbLogX.SetValue(False)
            self.cbLogY.SetValue(False)
        else:
            self.redraw_same_data()

    def crosshair_event(self, event):
        try:
            self.multiCursors.vertOn =self.cbXHair.GetValue()
            self.multiCursors.horizOn=self.cbXHair.GetValue()
            self.multiCursors._update()
        except:
            pass

    def scatter_select(self, event):
        self.cbScatter.SetValue(self.cbScatter.GetValue())
        self.redraw_same_data()

    def show_hide(self,panel,bShow):
        if bShow:
            panel.Show()
            self.slCtrl.Show()
        else:
            panel.Hide()
            self.slCtrl.Hide()

    @property
    def sharex(self):
        return self.cbSync.IsChecked() and (not self.pltTypePanel.cbPDF.GetValue())

    def set_subplots(self,nPlots):
        # Creating subplots
        for ax in self.fig.axes:
            self.fig.delaxes(ax)
        sharex=None
        for i in range(nPlots):
            # Vertical stack
            if i==0:
                ax=self.fig.add_subplot(nPlots,1,i+1)
                if self.sharex:
                    sharex=ax
            else:
                ax=self.fig.add_subplot(nPlots,1,i+1,sharex=sharex)
            # Horizontal stack
            #self.fig.add_subplot(1,nPlots,i+1)

    def onMouseMove(self, event):
        if event.inaxes:
            x, y = event.xdata, event.ydata
            if abs(x)<1000 and abs(x)>1e-4:
                self.lbCrossHairX.SetLabel("x={:10.5f}".format(x))
            else:
                self.lbCrossHairX.SetLabel("x={:10.3e}".format(x))
            if abs(y)<1000 and abs(y)>1e-4:
                self.lbCrossHairY.SetLabel("y={:10.5f}".format(y))
            else:
                self.lbCrossHairY.SetLabel("y={:10.3e}".format(y))

    def removeTools(self,event=None,Layout=True):
        try:
            # Python3
            self.toolSizer.Clear(delete_windows=True) # Delete Windows
        except:
            # Python2
            if hasattr(self,'toolPanel'):
                self.toolSizer.Remove(self.toolPanel)
                self.toolPanel.Destroy()
                del self.toolPanel
            self.toolSizer.Clear() # Delete Windows
        if Layout:
            self.plotsizer.Layout()

    def showTool(self,toolName=''):
        self.removeTools(Layout=False)
        # TODO dictionary
        if toolName=='LogDec':
            self.toolPanel=LogDecToolPanel(self)
        elif toolName=='Mask':
            self.toolPanel=MaskToolPanel(self)
        elif toolName=='FASTRadialAverage':
            self.toolPanel=RadialToolPanel(self)
        else:
            raise Exception('Unknown tool {}'.format(toolName))
        self.toolSizer.Add(self.toolPanel, 0, wx.EXPAND|wx.ALL, 5)
        self.plotsizer.Layout()

    def setPD_PDF(self,d,c):
        # ---PDF
        n=len(d.y)
        if d.yIsString:
            if n>100:
                Warn(self,'Dataset has string format and is too large to display')
                self.pltTypePanel.cbRegular.SetValue(True)
                return
            else:
                vc = c.value_counts().sort_index()
                d.x = vc.keys().tolist()
                d.y = vc/n # TODO counts/PDF option
                d.yIsString=False
                d.xIsString=True
        elif d.yIsDate:
            Warn(self,'Cannot plot PDF of dates')
            self.pltTypePanel.cbRegular.SetValue(True)
            return
        else:
            nBins=self.pdfPanel.scBins.GetValue()
            #min(int(n/10),50)
            if nBins>=n:
                nBins=n
                self.pdfPanel.scBins.SetValue(nBins)
            d.y, d.x = np.histogram(d.y[~np.isnan(d.y)], bins=nBins)
            dx   = d.x[1] - d.x[0]
            d.x  = d.x[:-1] + dx/2
            d.y  = d.y / (n*dx) # TODO counts /PDF option
        d.sx = d.sy;
        d.sy = 'PDF('+no_unit(d.sy)+')'
        iu = inverse_unit(d.sy)
        if len(iu)>0:
            d.sy += ' ['+ iu +']'

    def setPD_MinMax(self,d):
        if self.mmxPanel.cbyMinMax.IsChecked():
            if d.yIsString:
                Warn(self,'Cannot compute min-max for strings')
                self.mmxPanel.cbyMinMax.SetValue(False)
                #self.pltTypePanel.cbRegular.SetValue(True)
                return
            mi= np.nanmin(d.y)
            mx= np.nanmax(d.y)
            if mi == mx:
                d.y=d.y*0
            else:
                d.y = (d.y-mi)/(mx-mi)
        if self.mmxPanel.cbxMinMax.IsChecked():
            if d.xIsString:
                Warn(self,'Cannot compute min-max for strings')
                self.mmxPanel.cbxMinMax.SetValue(False)
                #self.pltTypePanel.cbRegular.SetValue(True)
                return
            mi= np.nanmin(d.x)
            mx= np.nanmax(d.x)
            if mi == mx:
                d.x=d.x*0
            else:
                d.x = (d.x-mi)/(mx-mi)

    def setPD_FFT(self,d):
        if d.yIsString or d.yIsDate:
            Warn(self,'Cannot plot FFT of dates or strings')
            self.pltTypePanel.cbRegular.SetValue(True)
        elif d.xIsString:
            Warn(self,'Cannot plot FFT if x axis is string')
            self.pltTypePanel.cbRegular.SetValue(True)
        else:
            output_type      = self.spcPanel.cbType.GetStringSelection()
            averaging        = self.spcPanel.cbAveraging.GetStringSelection()
            averaging_window = self.spcPanel.cbAveragingMethod.GetStringSelection()
            bDetrend         = self.spcPanel.cbDetrend.IsChecked()
            nExp             = self.spcPanel.scP2.GetValue()
            dt=None
            if d.xIsDate:
                dt = getDt(d.x)
            # --- Computing fft - x is freq, y is Amplitude
            d.x, d.y, Info = fft_wrap(d.x, d.y, dt=dt, output_type=output_type,averaging=averaging,averaging_window=averaging_window,detrend=bDetrend,nExp=nExp)
            # --- Setting plot options
            d.Info=Info
            d.xIsDate=False
            d.sy= 'FFT('+no_unit(d.sy)+')'
            if unit(d.sx)=='s':
                d.sx= 'Frequency [Hz]'
            else:
                d.sx= ''
            if hasattr(Info,'nExp') and Info.nExp!=nExp:
                self.spcPanel.scP2.SetValue(Info.nExp)
                self.spcPanel.updateP2(Info.nExp)


    def getPlotData(self,plotType):
        ID,SameCol=self.selPanel.getPlotDataSelection()
        del self.plotData
        self.plotData=[]
        tabs=self.selPanel.tabList.getTabs() # TODO
        for i,idx in enumerate(ID):
            d=PlotData();
            d.id = i
            d.it = idx[0]
            d.ix = idx[1]
            d.iy = idx[2]
            d.sx = idx[3]
            d.sy = idx[4]
            d.syl = ''
            d.st = idx[5]
            d.filename = tabs[d.it].filename
            d.tabname = tabs[d.it].active_name
            d.SameCol = SameCol
            d.x,d.xIsString,d.xIsDate,_ = tabs[d.it].getColumn(d.ix)
            d.y,d.yIsString,d.yIsDate,c = tabs[d.it].getColumn(d.iy)
            n=len(d.y)
            d.needChineseFont = has_chinese_char(d.sy) or has_chinese_char(d.sx)
            # Stats of the raw data
            #d.x0Min  = xMin(d)
            #d.x0Max  = xMax(d)
            d.y0Min  = yMin(d)
            d.y0Max  = yMax(d)
            d.y0Std  = yStd(d)
            d.y0Mean = yMean(d)
            d.n0     = (n,'{:d}'.format(n))
            # Possible change of data
            if plotType=='MinMax':
                self.setPD_MinMax(d) 
            elif plotType=='PDF':
                self.setPD_PDF(d,c)  
            elif plotType=='FFT':
                self.setPD_FFT(d) 
            self.plotData.append(d)

    def PD_Compare(self,mode):
        # --- Comparison
        PD=self.plotData
        sComp = self.cmpPanel.rbType.GetStringSelection()

        def getError(y,yref,method):
            if len(y)!=len(yref):
                raise NotImplementedError('Cannot compare signals of different lengths')
            if sComp=='Relative':
                if np.mean(np.abs(yref))<1e-7:
                    Error=(y-yRef)/(yRef+1)*100
                else:
                    Error=(y-yRef)/yRef*100
            elif sComp=='|Relative|':
                if np.mean(np.abs(yref))<1e-7:
                    Error=abs((y-yRef)/(yRef+1))*100
                else:
                    Error=abs((y-yRef)/yRef)*100
            elif sComp=='Ratio':
                if np.mean(np.abs(yref))<1e-7:
                    Error=(y+1)/(yRef+1)
                else:
                    Error=y/yRef
            elif sComp=='Absolute':
                Error=y-yRef
            else:
                raise Exception('Something wrong '+sComp)
            return Error

        def getErrorLabel(ylab=''):
            if len(ylab)>0:
                ylab=no_unit(ylab)
                ylab='in '+ylab+' '
            if sComp=='Relative':
                return 'Relative error '+ylab+'[%]';
            elif sComp=='|Relative|':
                return 'Abs. relative error '+ylab+'[%]';
            if sComp=='Ratio':
                return 'Ratio '+ylab.replace('in','of')+'[-]';
            elif sComp=='Absolute':
                usy   = unique([pd.sy for pd in PD])
                yunits= unique([unit(sy) for sy in usy])
                if len(yunits)==1 and len(yunits[0])>0:
                    return 'Absolute error '+ylab+'['+yunits[0]+']'
                else:
                    return 'Absolute error '+ylab;
            elif sComp=='Y-Y':
                return PD[0].sy

        xlabelAll=PD[0].sx

        
        if any([pd.yIsString for pd in PD]):
            Warn(self,'Cannot compare strings')
            self.pltTypePanel.cbRegular.SetValue(True)
            return
        if any([pd.yIsDate for pd in PD]):
            Warn(self,'Cannot compare dates with other values')
            self.pltTypePanel.cbRegular.SetValue(True)
            return


        if mode=='nTabs_1Col':
            ylabelAll=getErrorLabel(PD[1].sy)
            usy   = unique([pd.sy for pd in PD])
            #print('Compare - different tabs - 1 col')
            st  = [pd.st for pd in PD]
            if len(usy)==1:
               SS=usy[0] + ', '+ ' wrt. '.join(st[::-1])
               if sComp=='Y-Y':
                   xlabelAll=PD[0].st+', '+PD[0].sy
                   ylabelAll=PD[1].st+', '+PD[1].sy
            else:
                SS=' wrt. '.join(usy[::-1])
                if sComp=='Y-Y':
                    xlabelAll=PD[0].sy
                    ylabelAll=PD[1].sy

            xRef = PD[0].x
            yRef = PD[0].y
            PD[1].syl=SS
            y=np.interp(xRef,PD[1].x,PD[1].y)
            if sComp=='Y-Y':
                PD[1].x=yRef
                PD[1].y=y
            else:
                Error = getError(y,yRef,sComp)
                PD[1].x=xRef
                PD[1].y=Error
            PD[1].sx=xlabelAll
            PD[1].sy=ylabelAll
            self.plotData=[PD[1]]

        elif mode=='1Tab_nCols':
            # --- Compare one table - different columns
            #print('One Tab, different columns')
            ylabelAll=getErrorLabel()
            xRef = PD[0].x
            yRef = PD[0].y
            pdRef=PD[0]
            for pd in PD[1:]:
                if sComp=='Y-Y':
                    pd.syl = no_unit(pd.sy)+' wrt. '+no_unit(pdRef.sy)
                    pd.x   = yRef
                    pd.sx  = PD[0].sy
                else:
                    pd.syl = no_unit(pd.sy)+' wrt. '+no_unit(pdRef.sy)
                    pd.sx  = xlabelAll
                    pd.sy  = ylabelAll
                    Error  = getError(pd.y,yRef,sComp)
                    pd.x=xRef
                    pd.y=Error
            self.plotData=PD[1:]
        elif mode =='nTabs_SameCols':
            # --- Compare different tables, same column
            #print('Several Tabs, same columns')
            uiy=unique([pd.iy for pd in PD])
            uit=unique([pd.it for pd in PD])
            self.plotData=[]
            for iy in uiy:
                PD_SameCol=[pd for pd in PD if pd.iy==iy]
                xRef = PD_SameCol[0].x
                yRef = PD_SameCol[0].y
                ylabelAll=getErrorLabel(PD_SameCol[0].sy)
                for pd in PD_SameCol[1:]:
                    if pd.xIsString:
                        if len(xRef)==len(pd.x):
                            pass # fine able to interpolate
                        else:
                            Error(self,'X values have different length and are strings, cannot interpolate string. Use `Index` for x instead.')
                    else:
                        pd.y=np.interp(xRef,pd.x,pd.y)
                    if sComp=='Y-Y':
                        pd.x=yRef
                        pd.sx=PD_SameCol[0].st+', '+PD_SameCol[0].sy
                        if len(PD_SameCol)==1:
                            pd.sy =pd.st+', '+pd.sy
                        else:
                            pd.syl= pd.st
                    else:
                        if len(uit)<=2:
                            pd.syl = pd.st+' wrt. '+PD_SameCol[0].st+', '+pd.sy
                        else:
                            pd.syl = pd.st+'|'+pd.sy
                        pd.sx  = xlabelAll
                        pd.sy  = ylabelAll
                        Error = getError(pd.y,yRef,sComp)
                        pd.x=xRef
                        pd.y=Error
                    self.plotData.append(pd)




    def plot_all(self):
        self.multiCursors=[]
        axes=self.fig.axes

        bScatter=self.cbScatter.IsChecked()

        PD=self.plotData


        needChineseFont = any([pd.needChineseFont for pd in PD])
        if needChineseFont and self.specialFont is not None:
            font_options      = {'fontproperties': self.specialFont}
            font_options_legd = {'prop': self.specialFont}
        else:
            font_options      = {}
            font_options_legd = {}

        bAllNeg=True
        for ax in axes:
            # Plot data
            vDate=[PD[i].yIsDate for i in ax.iPD]
            if any(vDate) and len(vDate)>1:
                Error(self,'Cannot plot date and other value on the same axis')
                return

            #Keep me - tight axis, attempt to optimize
            #try:
            #    xMin=np.min([PD[i].x0Min[0] for i in ax.iPD])
            #    xMax=np.max([PD[i].x0Max[0] for i in ax.iPD])
            #    ax.set_xlim(xMin,xMax)
            #    ax.autoscale(False)
            #except:
            #    pass
            #try:
            #    yMin=np.min([PD[i].y0Min[0] for i in ax.iPD])
            #    yMax=np.max([PD[i].y0Max[0] for i in ax.iPD])
            #    ax.set_ylim(yMin,yMax)
            #    ax.autoscale(False)
            #except:
            #    pass


            for ipd in ax.iPD:
                pd=PD[ipd]
                if bScatter or len(pd.x)==1:
                    sty='o'
                else:
                    sty='-'
                ax.plot(pd.x,pd.y,sty,label=pd.syl,markersize=1)
                try:
                    bAllNeg=bAllNeg and  all(pd.y<=0)
                except:
                    pass # Dates

            # Log Axes
            if self.cbLogX.IsChecked():
                ax.set_xscale("log", nonposx='clip')
            if self.cbLogY.IsChecked():
                if bAllNeg:
                    pass
                else:
                    ax.set_yscale("log", nonposy='clip')

            # XLIM - TODO FFT ONLY NASTY
            if self.pltTypePanel.cbFFT.GetValue():
                try:
                    xlim=float(self.spcPanel.tMaxFreq.GetLineText(0))
                    if xlim>0:
                        ax.set_xlim([0,xlim])
                        pd=PD[ax.iPD[0]]
                        I=pd.x<xlim
                        ymin = np.min([np.min(PD[ipd].y[I]) for ipd in ax.iPD])
                        ax.set_ylim(bottom=ymin/2)
                except:
                    pass
            # Special Grids
            if self.pltTypePanel.cbCompare.GetValue():
                if self.cmpPanel.rbType.GetStringSelection()=='Y-Y':
                    xmin,xmax=ax.get_xlim()
                    ax.plot([xmin,xmax],[xmin,xmax],'k--',linewidth=0.5)

        # Labels
        axes[-1].set_xlabel(PD[axes[-1].iPD[0]].sx, **font_options)
        for ax in axes:
            usy = unique([PD[i].sy for i in ax.iPD])
            if len(usy)<=3:
                ax.set_ylabel(' and '.join(usy), **font_options) # consider legend
            else:
                ax.set_ylabel('')
        # Legend
        #print('sy :',[pd.sy for pd in PD])
        #print('syl:',[pd.syl for pd in PD])
        usyP0 = unique([PD[i].syl for i in axes[0].iPD])
        if  self.pltTypePanel.cbCompare.GetValue():
            for ax in axes:
                ax.legend(fancybox=False, loc=1, **font_options_legd)
        elif len(usyP0)>1:
            #axes[0].legend(fancybox=False, framealpha=1, loc=1, shadow=None)
            axes[0].legend(fancybox=False, loc=1, **font_options_legd)
        elif len(axes)>1 and len(axes)==len(PD):
            # Special case when we have subplots and all plots have the same label
            usy = unique([pd.sy for pd in PD])
            if len(usy)==1:
                for ax in axes:
                    ax.legend(fancybox=False, loc=1, **font_options_legd)
            
        # --- Cursors for each individual plot
        # NOTE: cursors needs to be stored in the object!
        #for ax in self.fig.axes:
        #    self.cursors.append(MyCursor(ax,horizOn=True, vertOn=False, useblit=True, color='gray', linewidth=0.5, linestyle=':'))
        # Vertical cusor for all, commonly
        bXHair = self.cbXHair.GetValue()
        self.multiCursors = MyMultiCursor(self.canvas, tuple(self.fig.axes), useblit=True, horizOn=bXHair, vertOn=bXHair, color='gray', linewidth=0.5, linestyle=':')

    def findPlotMode(self,PD):
        uTabs=unique([pd.it for pd in PD])
        usy=unique([pd.sy for pd in PD])
        uiy=unique([pd.iy for pd in PD])
        if len(uTabs)<=0:
            raise Exception('No Table. Contact developer')
        elif len(uTabs)==1:
            mode='1Tab_nCols'
        else:
            if PD[0].SameCol:
                mode='nTabs_SameCols'
            else:
                mode='nTabs_1Col'
        return mode

    def findSubPlots(self,PD,mode):
        uTabs = unique([pd.it for pd in PD])
        usy   = unique([pd.sy for pd in PD])
        bSubPlots = self.cbSub.IsChecked()
        bCompare  = self.pltTypePanel.cbCompare.GetValue() # NOTE bCompare somehow always 1Tab_nCols
        nSubPlots=1
        spreadBy='none'
        if mode=='1Tab_nCols':
            if bSubPlots:
                if bCompare:
                    nSubPlots=len(PD)
                    spreadBy='iy'
                else:
                    if len(uTabs)==1:
                        nSubPlots=len(PD)
                    else:
                        nSubPlots=len(usy)
                    spreadBy='iy'
        elif mode=='nTabs_SameCols':
            if bSubPlots:
                if bCompare:
                    print('>>>TODO ',mode,len(usy),len(uTabs))
                else:
                    if len(usy)==1:
                        # Temporary hack until we have an option for spread by tabs or col
                        nSubPlots=len(uTabs)
                        spreadBy='it'
                    else:
                        nSubPlots=len(usy)
                        spreadBy='iy'
        else:
            mode='nTabs_1Col'
            if bSubPlots:
                if bCompare:
                    print('>>> TODO',mode,len(uTabs))
                else:
                    nSubPlots=len(uTabs)
                    spreadBy='it'
        return nSubPlots,spreadBy

    def distributePlots(self,mode,nSubPlots,spreadBy):
        """ Assigns plot data to axes and axes to plot data """
        axes=self.fig.axes

        # Link plot data to axes
        if nSubPlots==1 or spreadBy=='none':
            axes[0].iPD=[i for i in range(len(self.plotData))]
        else:
            for ax in axes:
                ax.iPD=[]
            PD=self.plotData
            uTabs=unique([pd.it for pd in PD])
            uiy=unique([pd.iy for pd in PD])
            if spreadBy=='iy':
                for ipd,pd in enumerate(PD):
                    i=uiy.index(pd.iy)
                    axes[i].iPD.append(ipd)
            elif spreadBy=='it':
                for ipd,pd in enumerate(PD):
                    i=uTabs.index(pd.it)
                    axes[i].iPD.append(ipd)
            else:
                raise Exception('Wrong spreadby value')

    def setLegendLabels(self,mode):
        """ Set labels for legend """
        if mode=='1Tab_nCols':
            for pd in self.plotData:
                if self.pltTypePanel.cbMinMax.GetValue():
                    pd.syl = no_unit(pd.sy)
                else:
                    pd.syl = pd.sy

        elif mode=='nTabs_SameCols':
            for pd in self.plotData:
                pd.syl=pd.st

        elif mode=='nTabs_1Col':
            usy=unique([pd.sy for pd in self.plotData])
            if len(usy)==1:
                for pd in self.plotData:
                    pd.syl=pd.st
            else:
                for pd in self.plotData:
                    if self.pltTypePanel.cbMinMax.GetValue():
                        pd.syl=no_unit(pd.sy)
                    else:
                        pd.syl=pd.sy #pd.syl=pd.st + ' - '+pd.sy



    def empty(self):
        self.cleanPlot()

    def clean_memory(self):
        if hasattr(self,'plotData'):
            del self.plotData
            self.plotData=[]
            for ax in self.fig.axes:
                ax.iPD=[]
                self.fig.delaxes(ax)
            gc.collect()

    def clean_memory_plot(self):
        pass

    def cleanPlot(self):
        for ax in self.fig.axes:
            if hasattr(ax,'iPD'):
                del ax.iPD
            self.fig.delaxes(ax)
        gc.collect()
        self.fig.add_subplot(111)
        ax = self.fig.axes[0]
        ax.set_axis_off()
        #ax.plot(1,1)
        self.canvas.draw()
        gc.collect()

    def redraw(self):
        self._redraw()
        if self.infoPanel is not None:
            self.infoPanel.showStats(self.plotData,self.pltTypePanel.plotType())

    def redraw_same_data(self):
        self._redraw_same_data()

    def _redraw_same_data(self):
        if len(self.plotData)==0: 
            self.cleanPlot();
            return

        mode=self.findPlotMode(self.plotData)
        nPlots,spreadBy=self.findSubPlots(self.plotData,mode)

        self.clean_memory_plot()
        self.set_subplots(nPlots)
        self.distributePlots(mode,nPlots,spreadBy)

        if not self.pltTypePanel.cbCompare.GetValue():
            self.setLegendLabels(mode)

        self.plot_all()
        self.canvas.draw()

    def _redraw(self):
        self.clean_memory()
        self.getPlotData(self.pltTypePanel.plotType())
        if len(self.plotData)==0: 
            self.cleanPlot();
            return

        mode=self.findPlotMode(self.plotData)
        if self.pltTypePanel.cbCompare.GetValue():
            self.PD_Compare(mode)
            if len(self.plotData)==0: 
                self.cleanPlot();
                return
        self._redraw_same_data()
Exemple #22
0
class AppForm(QMainWindow, QWidget):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        icon = QIcon("32959206.png")
        self.setWindowIcon(icon)
        self.setWindowTitle('Graphic3D')
        self.setup(self)
        self.create_main_frame()
        self.create_menu()

    def setup(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.setStyleSheet(
            "#MainWindow { border-image: url(bg.png) 0 0 0 0 stretch stretch; }"
        )
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

    def create_menu(self):
        #self.statusBar()
        #self.setFocus()
        openfile = QAction(QIcon('icons/Blue_Flower.ico'), 'Open', self)
        openfile.setShortcut('Ctrl+O')
        openfile.setStatusTip('Open new file')
        openfile.triggered.connect(self.openfile)
        quitui = QAction(QIcon('icons/Blue_Flower.ico'), 'Quit', self)
        quitui.setShortcut('Ctrl+Q')
        quitui.setStatusTip('Quit')
        quitui.triggered.connect(self.close)
        saveplot = QAction(QIcon('icons/Blue_Flower.ico'), 'Save Plot', self)
        saveplot.setShortcut('Ctrl+S')
        saveplot.setStatusTip('Save Plot')
        saveplot.triggered.connect(self.save_plot)
        about = QAction(QIcon('icons/Blue_Flower.ico'), 'About', self)
        about.setShortcut('Ctrl+A')
        about.setStatusTip('About')
        about.triggered.connect(self.on_about)

        menubar = self.menuBar()
        file = menubar.addMenu('&File')
        file.addAction(openfile)
        file.addAction(saveplot)
        file.addAction(quitui)
        helpabout = menubar.addMenu('&Help')
        helpabout.addAction(about)

    def mainaxes(self):
        self.axes = self.fig.add_subplot(1, 2, 1, projection='3d')
        self.axes.set_alpha(0)
        self.axes.patch.set_alpha(0)
        self.axes.set_aspect('equal')
        self.axes.set_xlim3d(-1, 42)
        self.axes.set_ylim3d(-1, 42)
        self.axes.set_zlim3d(-1, 63)
        self.axes.set_xlabel('x-axis')
        self.axes.set_ylabel('y-axis')
        self.axes.set_zlabel('z-axis')
        xmajorLocator = MultipleLocator(5)
        ymajorLocator = MultipleLocator(5)
        zmajorLocator = MultipleLocator(5)
        self.axes.xaxis.set_major_locator(xmajorLocator)
        self.axes.yaxis.set_major_locator(ymajorLocator)
        self.axes.zaxis.set_major_locator(zmajorLocator)

    def create_main_frame(self):
        #self.main_frame = QWidget()
        self.dpi = 100
        self.fig = Figure((15.0, 12.0), dpi=self.dpi)
        self.fig.set_facecolor('none')
        self.canvas = FigureCanvas(self.fig)
        #self.canvas.setParent(self.main_frame)
        self.canvas.setParent(self.centralwidget)
        self.canvas.setStyleSheet("background-color:transparent;")
        # 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.fig.subplots_adjust(left=0.03,
                                 bottom=0.08,
                                 right=0.95,
                                 top=0.95,
                                 wspace=0.2,
                                 hspace=0.2)
        self.mainaxes()
        xmajorLocator = MultipleLocator(5)
        ymajorLocator = MultipleLocator(5)
        xminorLocator = MultipleLocator(1)
        yminorLocator = MultipleLocator(1)
        self.axx = self.fig.add_subplot(243)
        self.axx.set_xlim(0, 41)
        self.axx.set_ylim(0, 62)
        self.axx.grid(color='k', linestyle='--', linewidth=0.5, which='minor')
        self.axx.xaxis.set_major_locator(xmajorLocator)
        self.axx.yaxis.set_major_locator(ymajorLocator)
        self.axx.xaxis.set_minor_locator(xminorLocator)
        self.axx.yaxis.set_minor_locator(yminorLocator)
        self.axx.set_title('Y-Z section', loc='center')
        #self.axx.set_aspect('equal')
        self.axy = self.fig.add_subplot(244)
        self.axy.set_xlim(0, 41)
        self.axy.set_ylim(0, 62)
        self.axy.grid(color='k', linestyle='--', linewidth=0.5, which='minor')
        self.axy.xaxis.set_major_locator(xmajorLocator)
        self.axy.yaxis.set_major_locator(ymajorLocator)
        self.axy.xaxis.set_minor_locator(xminorLocator)
        self.axy.yaxis.set_minor_locator(yminorLocator)
        self.axy.set_title('X-Z section', loc='center')
        #self.axy.set_aspect('equal')
        self.axz = self.fig.add_subplot(248)
        self.axz.set_xlim(0, 41)
        self.axz.set_ylim(0, 41)
        self.axz.grid(color='k', linestyle='--', linewidth=0.5, which='minor')
        xmajorLocator = MultipleLocator(5)
        ymajorLocator = MultipleLocator(5)
        xminorLocator = MultipleLocator(1)
        yminorLocator = MultipleLocator(1)
        self.axz.xaxis.set_major_locator(xmajorLocator)
        self.axz.yaxis.set_major_locator(ymajorLocator)
        self.axz.xaxis.set_minor_locator(xminorLocator)
        self.axz.yaxis.set_minor_locator(yminorLocator)
        self.axz.set_title('X-Y section', loc='center')
        #self.axz.set_aspect('equal')
        self.logo = self.fig.add_subplot(247)
        self.logo.set_aspect('equal')
        #self.logo.set_xlim(-100,300)
        #self.logo.set_ylim(250,-70)
        img = mpimg.imread('color.png')
        imgplot = self.logo.imshow(img)
        self.logo.set_axis_off()
        self.fig.canvas.mpl_connect('button_press_event', self.onpressx)
        self.fig.canvas.mpl_connect('button_press_event', self.onpressy)
        self.fig.canvas.mpl_connect('button_press_event', self.onpressz)

        font = QFont()
        font.setFamily('Comic Sans MS')
        font.setBold(True)
        #大小
        font.setPointSize(10)
        font.setWeight(60)
        slider_labelcolor = QLabel('Show:')
        slider_labelcolor.setFont(font)
        #slider_labelcolor.setText("<font color=%s>%s</font>" %('#000000', "Show:"))

        self.comboboxcolor = QComboBox(self)
        colors = [
            'View All', 'vsave < 3', '3 < vsave < 4', '4 < vsave < 5',
            '5 < vsave < 6', '6 < vsave < 7', '8 < vsave'
        ]
        self.comboboxcolor.addItems(colors)
        #self.comboboxcolor.setMaxVisibleItems(5)
        self.comboboxcolor.setStyleSheet(
            "border: 1px solid gray;border-radius:3px;padding: 1px 18px 1px 3px;min-width: 5em;selection-background-color: darkgray;"
        )
        self.comboboxcolor.setFont(font)
        self.comboboxcolor.activated.connect(self.onecolor)

        self.returnbtn = QPushButton()
        self.returnbtn.setFont(font)
        self.returnbtn.clicked.connect(self.zoom)
        self.returnbtn.setStyleSheet(
            'QPushButton{border-image:url(return.png)}')
        self.zoombutton = QPushButton()
        self.zoombutton.setText('ZOOM')
        self.zoombutton.setFont(font)
        self.zoombutton.setStyleSheet(
            "color:white;background-color:black;border-radius:4px;min-width: 5em;"
        )
        self.i = 0
        self.zoombutton.clicked.connect(self.count)
        self.sliderfig = QSlider(Qt.Horizontal)
        self.sliderfig.setRange(0, 99)
        self.sliderfig.setStyleSheet(
            "QSlider::handle:horizontal { border-radius:3px;border-image:url(rb.png);}"
        )
        self.sliderfig.valueChanged.connect(self.zoomin)
        self.labezoomin = QLabel(self)
        self.labezoomout = QLabel(self)
        self.pixmapin = QPixmap('zo_opt.png')
        self.labezoomin.setPixmap(self.pixmapin)
        self.pixmapout = QPixmap('zi_opt.png')
        self.labezoomout.setPixmap(self.pixmapout)

        textboxx_label = QLabel('  Y-Z section : ')
        self.textboxx = QLineEdit(self)
        self.textboxx.setText('0')
        textboxx_label.setFont(font)
        self.textboxx.setStyleSheet(
            "border: 1px solid gray;border-radius:4px;padding: 1px 18px 1px 3px;min-width: 3em;"
        )
        textboxy_label = QLabel('  X-Z section : ')
        self.textboxy = QLineEdit(self)
        self.textboxy.setText('0')
        textboxy_label.setFont(font)
        self.textboxy.setStyleSheet(
            "border: 1px solid gray;border-radius:4px;padding: 1px 18px 1px 3px;min-width: 3em;"
        )
        textboxz_label = QLabel('  X-Y section : ')
        self.textboxz = QLineEdit(self)
        self.textboxz.setText('0')
        textboxz_label.setFont(font)
        self.textboxz.setStyleSheet(
            "border: 1px solid gray;border-radius:4px;padding: 1px 18px 1px 3px;min-width: 3em;"
        )

        self.drawbutton = QPushButton()
        self.drawbutton.setText('DRAW')
        self.drawbutton.setFont(font)
        self.drawbutton.setStyleSheet(
            "color:white;background-color:black;border-radius:4px;min-width: 5em;"
        )
        self.drawbutton.clicked.connect(self.drawsection)

        hbox = QHBoxLayout()

        for w in [
                self.zoombutton, self.returnbtn, self.labezoomin,
                self.sliderfig, self.labezoomout, slider_labelcolor,
                self.comboboxcolor, textboxx_label, self.textboxx,
                textboxy_label, self.textboxy, textboxz_label, self.textboxz,
                self.drawbutton
        ]:
            hbox.addWidget(w)
            hbox.setAlignment(w, Qt.AlignVCenter)

        vbox = QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(self.canvas)

        #self.main_frame.setLayout(vbox)
        #self.setCentralWidget(self.main_frame)
        self.setCentralWidget(self.centralwidget)
        self.centralwidget.setLayout(vbox)
        #self.setCentralWidget.setMouseTracking(True)

    def on_about(self):
        msg = """
                    * Choose .pvel file
* Input the number which scale of the 
  sections in three axis separately
  you want to display then push the 
  'DRAW' button to show the 2D sections
* Use the slider to zoom in/out the 
  3D model of the .pvel file
* You can display single layer in
  3D model by using the combobox
                                                         """
        QMessageBox.about(self, "About Graphic3D", msg.strip())

    def count(self):
        self.i += 1
        if self.i % 2 == 1:
            self.zoombutton.setStyleSheet(
                "color:white;background-color:red;border-radius:4px;min-width: 5em;"
            )
            self.zoomcenter()
            self.zoom()
        else:
            self.zoombutton.setStyleSheet(
                "color:white;background-color:black;border-radius:4px;min-width: 5em;"
            )
            self.setMouseTracking(False)
            self.fig.delaxes(self.zoomin)
            self.mainaxes()
            self.on_draw()

    def zoomcenter(self):
        if self.i % 2 == 1:
            #self.fig.canvas.mpl_connect('button_press_event',self.onpress)
            self.fig.canvas.mpl_connect('button_release_event', self.onrelease)
            self.pressevent = None

    def onpressx(self, event):
        if event.inaxes != self.axx:
            return
        self.pressevent = None
        self.x = event.xdata
        self.y = event.ydata
        val = self.textboxx.text()
        v = int(val)
        x = int(self.x)
        y = int(self.y)
        print(v, x, y)
        msg = "You've clicked on a point : ( %s ," % v + " %s ," % x + " %s )\n" % y + "Value:%f " % self.data[
            v, x, y]
        QMessageBox.information(self, "Click!", msg)

    def onpressy(self, event):
        if event.inaxes != self.axy:
            return
        self.pressevent = None
        self.x = event.xdata
        self.y = event.ydata
        val = self.textboxy.text()
        v = int(val)
        x = int(self.x)
        y = int(self.y)
        print(x, v, y)
        msg = "You've clicked on a point : ( %s ," % x + " %s ," % v + " %s )\n" % y + "Value:%f " % self.data[
            x, v, y]
        QMessageBox.information(self, "Click!", msg)

    def onpressz(self, event):
        if event.inaxes != self.axz:
            return
        self.pressevent = None
        self.x = event.xdata
        self.y = event.ydata
        val = self.textboxz.text()
        v = int(val)
        x = int(self.x)
        y = int(self.y)
        print(x, y, v)
        msg = "You've clicked on a point : ( %s ," % x + " %s ," % y + " %s )\n" % v + "Value:%f " % self.data[
            x, y, v]
        QMessageBox.information(self, "Click!", msg)

    def onrelease(self, event):
        self.pressevent = None
        self.x = event.xdata
        self.y = event.ydata
        print(self.x, self.y)

    def zoom(self):
        extent = self.axes.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        self.fig.savefig('axeszoom.png',
                         bbox_inches=extent.expanded(1.1, 1.2),
                         dpi=200,
                         transparent=True)
        self.fig.delaxes(self.axes)
        self.zoomin = self.fig.add_subplot(121)
        img = mpimg.imread('axeszoom.png')
        imgplot = self.zoomin.imshow(img)
        self.setMouseTracking(True)
        self.zoomin.set_xlim(150, 1650)
        self.zoomin.set_ylim(1750, 180)
        #self.zoomin.set_aspect('equal')
        self.zoomin.set_alpha(0)
        self.zoomin.patch.set_alpha(0)
        self.zoomin.set_axis_off()
        print('AA')

    def zoomin(self):
        print(self.sliderfig.value())
        z = self.sliderfig.value()
        self.zoomin.set_xlim(self.x - (self.x - 150) * (100 - z) / 100,
                             self.x + (1650 - self.x) * (100 - z) / 100)
        self.zoomin.set_ylim(self.y + (1750 - self.y) * (100 - z) / 100,
                             self.y - (self.y - 180) * (100 - z) / 100)
        #self.zoomin.set_aspect('equal')
        print('aa')

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

        path = QFileDialog.getSaveFileName(self, 'Save file', '', file_choices)
        extent = self.axes.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        self.fig.savefig("3Dmodel.png",
                         bbox_inches=extent.expanded(1.2, 1.2),
                         dpi=200,
                         transparent=True)
        extent = self.axx.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        self.fig.savefig("YZ_section_%s.png" % self.textboxx.text(),
                         bbox_inches=extent.expanded(1.2, 1.2),
                         dpi=200,
                         transparent=True)
        extent = self.axy.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        self.fig.savefig("XZ_section_%s.png" % self.textboxy.text(),
                         bbox_inches=extent.expanded(1.2, 1.2),
                         dpi=200,
                         transparent=True)
        extent = self.axz.get_window_extent().transformed(
            self.fig.dpi_scale_trans.inverted())
        self.fig.savefig("XY_section_%s.png" % self.textboxz.text(),
                         bbox_inches=extent.expanded(1.2, 1.2),
                         dpi=200,
                         transparent=True)
        if path:
            self.canvas.print_figure(path[0], dpi=self.dpi)
            self.statusBar().showMessage('Saved to %s' % path, 2000)

    @jit
    def openfile(self):
        filename, _ = QFileDialog.getOpenFileName(self, 'Open file', './')
        file = open(filename)
        print(filename)
        line = file.readline()
        self.test = []
        while line:
            fline = float(line)
            if fline == 0:
                break
            else:
                self.test.append(fline)
                line = file.readline()

        self.data = np.zeros((41, 41, 62), dtype=np.float)
        self.color = np.zeros((41, 41, 62), dtype=np.int)
        i = 0
        j = 0
        k = 0
        x = 0
        while j < 41:
            k = 0
            while k < 62:
                i = 0
                while i < 41:
                    self.data[i, j, k] = self.test[x]

                    if self.test[x] < 3:
                        self.color[i, j, k] = 0
                    elif self.test[x] > 3 and self.test[x] < 4:
                        self.color[i, j, k] = 1
                    elif self.test[x] > 4 and self.test[x] < 5:
                        self.color[i, j, k] = 2
                    elif self.test[x] > 5 and self.test[x] < 6:
                        self.color[i, j, k] = 3
                    elif self.test[x] > 6 and self.test[x] < 7:
                        self.color[i, j, k] = 4
                    elif self.test[x] > 7 and self.test[x] < 8:
                        self.color[i, j, k] = 5
                    elif self.test[x] > 8:
                        self.color[i, j, k] = 6
                    x = x + 1
                    i = i + 1
                k = k + 1
            j = j + 1
        print(self.color[40, 40, 61])
        print(self.test[104221])
        self.on_draw()

    @jit
    def on_draw(self):
        b = 0
        while b < 41:
            c = 0
            while c < 62:
                self.edges = [[(0, 0 + b, 0 + c), (1, 0 + b, 0 + c),
                               (1, 1 + b, 0 + c), (0, 1 + b, 0 + c)],
                              [(1, 0 + b, 0 + c), (1, 1 + b, 0 + c),
                               (1, 1 + b, 1 + c), (1, 0 + b, 1 + c)],
                              [(0, 1 + b, 0 + c), (0, 1 + b, 1 + c),
                               (1, 1 + b, 1 + c), (1, 1 + b, 0 + c)],
                              [(0, 1 + b, 1 + c), (0, 1 + b, 0 + c),
                               (0, 0 + b, 0 + c), (0, 0 + b, 1 + c)],
                              [(0, 0 + b, 0 + c), (0, 0 + b, 1 + c),
                               (1, 0 + b, 1 + c), (1, 0 + b, 0 + c)],
                              [(0, 1 + b, 1 + c), (0, 0 + b, 1 + c),
                               (1, 0 + b, 1 + c), (1, 1 + b, 1 + c)]]
                self.faces = Poly3DCollection(self.edges,
                                              color='k',
                                              linewidth=0.5,
                                              zorder=1)
                if self.color[0, b, c] == 0:
                    self.faces.set_facecolor((1, 0, 0.1, 1))
                elif self.color[0, b, c] == 1:
                    self.faces.set_facecolor((1, 0.5, 0, 1))
                elif self.color[0, b, c] == 2:
                    self.faces.set_facecolor((1, 1, 0, 1))
                elif self.color[0, b, c] == 3:
                    self.faces.set_facecolor((0.5, 1, 0, 1))
                elif self.color[0, b, c] == 4:
                    self.faces.set_facecolor((0, 1, 1, 1))
                elif self.color[0, b, c] == 5:
                    self.faces.set_facecolor((0, 0, 1, 1))
                elif self.color[0, b, c] == 6:
                    self.faces.set_facecolor((0.5, 0.2, 0.9, 1))
                self.axes.add_collection3d(self.faces)
                c = c + 1
            b = b + 1

        b = 0
        while b < 41:
            c = 0
            while c < 62:
                self.edges = [[(40, 0 + b, 0 + c), (41, 0 + b, 0 + c),
                               (41, 1 + b, 0 + c), (40, 1 + b, 0 + c)],
                              [(41, 0 + b, 0 + c), (41, 1 + b, 0 + c),
                               (41, 1 + b, 1 + c), (41, 0 + b, 1 + c)],
                              [(40, 1 + b, 0 + c), (40, 1 + b, 1 + c),
                               (41, 1 + b, 1 + c), (41, 1 + b, 0 + c)],
                              [(40, 1 + b, 1 + c), (40, 1 + b, 0 + c),
                               (40, 0 + b, 0 + c), (40, 0 + b, 1 + c)],
                              [(40, 0 + b, 0 + c), (40, 0 + b, 1 + c),
                               (41, 0 + b, 1 + c), (41, 0 + b, 0 + c)],
                              [(40, 1 + b, 1 + c), (40, 0 + b, 1 + c),
                               (41, 0 + b, 1 + c), (41, 1 + b, 1 + c)]]
                self.faces = Poly3DCollection(self.edges,
                                              color='k',
                                              linewidth=0.5,
                                              zorder=1)
                if self.color[40, b, c] == 0:
                    self.faces.set_facecolor((1, 0, 0.1, 1))
                elif self.color[40, b, c] == 1:
                    self.faces.set_facecolor((1, 0.5, 0, 1))
                elif self.color[40, b, c] == 2:
                    self.faces.set_facecolor((1, 1, 0, 1))
                elif self.color[40, b, c] == 3:
                    self.faces.set_facecolor((0.5, 1, 0, 1))
                elif self.color[40, b, c] == 4:
                    self.faces.set_facecolor((0, 1, 1, 1))
                elif self.color[40, b, c] == 5:
                    self.faces.set_facecolor((0, 0, 1, 1))
                elif self.color[40, b, c] == 6:
                    self.faces.set_facecolor((0.5, 0.2, 0.9, 1))
                self.axes.add_collection3d(self.faces)
                c = c + 1
            b = b + 1

        a = 0
        while a < 41:
            c = 0
            while c < 62:
                self.edges = [[(0 + a, 40, 0 + c), (1 + a, 40, 0 + c),
                               (1 + a, 41, 0 + c), (0 + a, 41, 0 + c)],
                              [(1 + a, 40, 0 + c), (1 + a, 41, 0 + c),
                               (1 + a, 41, 1 + c), (1 + a, 40, 1 + c)],
                              [(0 + a, 41, 0 + c), (0 + a, 41, 1 + c),
                               (1 + a, 41, 1 + c), (1 + a, 41, 0 + c)],
                              [(0 + a, 41, 1 + c), (0 + a, 41, 0 + c),
                               (0 + a, 40, 0 + c), (0 + a, 40, 1 + c)],
                              [(0 + a, 40, 0 + c), (0 + a, 40, 1 + c),
                               (1 + a, 40, 1 + c), (1 + a, 40, 0 + c)],
                              [(0 + a, 41, 1 + c), (0 + a, 40, 1 + c),
                               (1 + a, 40, 1 + c), (1 + a, 41, 1 + c)]]
                self.faces = Poly3DCollection(self.edges,
                                              color='k',
                                              linewidth=0.5,
                                              zorder=1)
                if self.color[a, 40, c] == 0:
                    self.faces.set_facecolor((1, 0, 0.1, 1))
                elif self.color[a, 40, c] == 1:
                    self.faces.set_facecolor((1, 0.5, 0, 1))
                elif self.color[a, 40, c] == 2:
                    self.faces.set_facecolor((1, 1, 0, 1))
                elif self.color[a, 40, c] == 3:
                    self.faces.set_facecolor((0.5, 1, 0, 1))
                elif self.color[a, 40, c] == 4:
                    self.faces.set_facecolor((0, 1, 1, 1))
                elif self.color[a, 40, c] == 5:
                    self.faces.set_facecolor((0, 0, 1, 1))
                elif self.color[a, 40, c] == 6:
                    self.faces.set_facecolor((0.5, 0.2, 0.9, 1))
                self.axes.add_collection3d(self.faces)
                c = c + 1
            a = a + 1

        a = 0
        while a < 41:
            c = 0
            while c < 62:
                self.edges = [[(0 + a, 0, 0 + c), (1 + a, 0, 0 + c),
                               (1 + a, 1, 0 + c), (0 + a, 1, 0 + c)],
                              [(1 + a, 0, 0 + c), (1 + a, 1, 0 + c),
                               (1 + a, 1, 1 + c), (1 + a, 0, 1 + c)],
                              [(0 + a, 1, 0 + c), (0 + a, 1, 1 + c),
                               (1 + a, 1, 1 + c), (1 + a, 1, 0 + c)],
                              [(0 + a, 1, 1 + c), (0 + a, 1, 0 + c),
                               (0 + a, 0, 0 + c), (0 + a, 0, 1 + c)],
                              [(0 + a, 0, 0 + c), (0 + a, 0, 1 + c),
                               (1 + a, 0, 1 + c), (1 + a, 0, 0 + c)],
                              [(0 + a, 1, 1 + c), (0 + a, 0, 1 + c),
                               (1 + a, 0, 1 + c), (1 + a, 1, 1 + c)]]
                self.faces = Poly3DCollection(self.edges,
                                              color='k',
                                              linewidth=0.5,
                                              zorder=1)
                if self.color[a, 0, c] == 0:
                    self.faces.set_facecolor((1, 0, 0.1, 1))
                elif self.color[a, 0, c] == 1:
                    self.faces.set_facecolor((1, 0.5, 0, 1))
                elif self.color[a, 0, c] == 2:
                    self.faces.set_facecolor((1, 1, 0, 1))
                elif self.color[a, 0, c] == 3:
                    self.faces.set_facecolor((0.5, 1, 0, 1))
                elif self.color[a, 0, c] == 4:
                    self.faces.set_facecolor((0, 1, 1, 1))
                elif self.color[a, 0, c] == 5:
                    self.faces.set_facecolor((0, 0, 1, 1))
                elif self.color[a, 0, c] == 6:
                    self.faces.set_facecolor((0.5, 0.2, 0.9, 1))
                self.axes.add_collection3d(self.faces)
                c = c + 1
            a = a + 1

        a = 0
        while a < 41:
            b = 0
            while b < 41:
                self.edges = [[(0 + a, 0 + b, 0), (1 + a, 0 + b, 0),
                               (1 + a, 1 + b, 0), (0 + a, 1 + b, 0)],
                              [(1 + a, 0 + b, 0), (1 + a, 1 + b, 0),
                               (1 + a, 1 + b, 1), (1 + a, 0 + b, 1)],
                              [(0 + a, 1 + b, 0), (0 + a, 1 + b, 1),
                               (1 + a, 1 + b, 1), (1 + a, 1 + b, 0)],
                              [(0 + a, 1 + b, 1), (0 + a, 1 + b, 0),
                               (0 + a, 0 + b, 0), (0 + a, 0 + b, 1)],
                              [(0 + a, 0 + b, 0), (0 + a, 0 + b, 1),
                               (1 + a, 0 + b, 1), (1 + a, 0 + b, 0)],
                              [(0 + a, 1 + b, 1), (0 + a, 0 + b, 1),
                               (1 + a, 0 + b, 1), (1 + a, 1 + b, 1)]]
                self.faces = Poly3DCollection(self.edges,
                                              color='k',
                                              linewidth=0.5,
                                              zorder=1)

                if self.color[a, b, 0] == 0:
                    self.faces.set_facecolor((1, 0, 0.1, 1))
                elif self.color[a, b, 0] == 1:
                    self.faces.set_facecolor((1, 0.5, 0, 1))
                elif self.color[a, b, 0] == 2:
                    self.faces.set_facecolor((1, 1, 0, 1))
                elif self.color[a, b, 0] == 3:
                    self.faces.set_facecolor((0.5, 1, 0, 1))
                elif self.color[a, b, 0] == 4:
                    self.faces.set_facecolor((0, 1, 1, 1))
                elif self.color[a, b, 0] == 5:
                    self.faces.set_facecolor((0, 0, 1, 1))
                elif self.color[a, b, 0] == 6:
                    self.faces.set_facecolor((0.5, 0.2, 0.9, 1))
                self.axes.add_collection3d(self.faces)
                b = b + 1
            a = a + 1

        a = 0
        while a < 41:
            b = 0
            while b < 41:
                self.edges = [[(0 + a, 0 + b, 61), (1 + a, 0 + b, 61),
                               (1 + a, 1 + b, 61), (0 + a, 1 + b, 61)],
                              [(1 + a, 0 + b, 61), (1 + a, 1 + b, 61),
                               (1 + a, 1 + b, 62), (1 + a, 0 + b, 62)],
                              [(0 + a, 1 + b, 61), (0 + a, 1 + b, 62),
                               (1 + a, 1 + b, 62), (1 + a, 1 + b, 61)],
                              [(0 + a, 1 + b, 62), (0 + a, 1 + b, 61),
                               (0 + a, 0 + b, 61), (0 + a, 0 + b, 62)],
                              [(0 + a, 0 + b, 61), (0 + a, 0 + b, 62),
                               (1 + a, 0 + b, 62), (1 + a, 0 + b, 61)],
                              [(0 + a, 1 + b, 62), (0 + a, 0 + b, 62),
                               (1 + a, 0 + b, 62), (1 + a, 1 + b, 62)]]
                self.faces = Poly3DCollection(self.edges,
                                              color='k',
                                              linewidth=0.5,
                                              zorder=1)
                if self.color[a, b, 61] == 0:
                    self.faces.set_facecolor((1, 0, 0.1, 1))
                elif self.color[a, b, 61] == 1:
                    self.faces.set_facecolor((1, 0.5, 0, 1))
                elif self.color[a, b, 61] == 2:
                    self.faces.set_facecolor((1, 1, 0, 1))
                elif self.color[a, b, 61] == 3:
                    self.faces.set_facecolor((0.5, 1, 0, 1))
                elif self.color[a, b, 61] == 4:
                    self.faces.set_facecolor((0, 1, 1, 1))
                elif self.color[a, b, 61] == 5:
                    self.faces.set_facecolor((0, 0, 1, 1))
                elif self.color[a, b, 61] == 6:
                    self.faces.set_facecolor((0.5, 0.2, 0.9, 1))
                self.axes.add_collection3d(self.faces)
                b = b + 1
            a = a + 1

    @jit
    def coloronly(self, index, r, b, g, a):
        self.canvas.draw()
        self.axes.cla()
        self.axes.set_xlim3d(-1, 42)
        self.axes.set_ylim3d(-1, 42)
        self.axes.set_zlim3d(-1, 63)
        xmajorLocator = MultipleLocator(5)
        ymajorLocator = MultipleLocator(5)
        zmajorLocator = MultipleLocator(5)
        self.axes.xaxis.set_major_locator(xmajorLocator)
        self.axes.yaxis.set_major_locator(ymajorLocator)
        self.axes.zaxis.set_major_locator(zmajorLocator)
        self.axes.set_alpha(0)
        self.axes.patch.set_alpha(0)
        i = 0
        while i < 41:
            j = 0
            while j < 41:
                k = 0
                while k < 62:
                    if self.color[i, j, k] == index:
                        print(self.color[i, j, k], index)
                        self.edges = [[(0 + i, 0 + j, 0 + k),
                                       (1 + i, 0 + j, 0 + k),
                                       (1 + i, 1 + j, 0 + k),
                                       (0 + i, 1 + j, 0 + k)],
                                      [(1 + i, 0 + j, 0 + k),
                                       (1 + i, 1 + j, 0 + k),
                                       (1 + i, 1 + j, 1 + k),
                                       (1 + i, 0 + j, 1 + k)],
                                      [(0 + i, 1 + j, 0 + k),
                                       (0 + i, 1 + j, 1 + k),
                                       (1 + i, 1 + j, 1 + k),
                                       (1 + i, 1 + j, 0 + k)],
                                      [(0 + i, 1 + j, 1 + k),
                                       (0 + i, 1 + j, 0 + k),
                                       (0 + i, 0 + j, 0 + k),
                                       (0 + i, 0 + j, 1 + k)],
                                      [(0 + i, 0 + j, 0 + k),
                                       (0 + i, 0 + j, 1 + k),
                                       (1 + i, 0 + j, 1 + k),
                                       (1 + i, 0 + j, 0 + k)],
                                      [(0 + i, 1 + j, 1 + k),
                                       (0 + i, 0 + j, 1 + k),
                                       (1 + i, 0 + j, 1 + k),
                                       (1 + i, 1 + j, 1 + k)]]
                        self.faces = Poly3DCollection(self.edges,
                                                      color='k',
                                                      linewidth=0.5,
                                                      zorder=1)
                        self.faces.set_facecolor((r, b, g, a))
                        self.axes.add_collection3d(self.faces)
                    k = k + 1
                j = j + 1
            i = i + 1
        print('finish', r, b, g, a)
        self.canvas.draw()

    def onecolor(self):
        r = 0
        b = 0
        g = 0
        a = 0
        index = self.comboboxcolor.currentIndex()
        print(index * index)
        if index == 0:
            self.on_draw()
        else:
            if index == 1:
                r = 1
                b = 0
                g = 0.1
                a = 1
            elif index == 2:
                r = 1
                b = 0.5
                g = 0
                a = 1
            elif index == 3:
                r = 1
                b = 1
                g = 0
                a = 1
            elif index == 4:
                r = 0.5
                b = 1
                g = 0
                a = 1
            elif index == 5:
                r = 0
                b = 1
                g = 1
                a = 1
            elif index == 6:
                r = 0
                b = 0
                g = 1
                a = 1
            elif index == 7:
                r = 0.5
                b = 0.2
                g = 0.9
                a = 1
            self.coloronly(index - 1, r, b, g, a)

    def drawsection(self):

        xsec = self.textboxx.text()
        ysec = self.textboxy.text()
        zsec = self.textboxz.text()
        #self.plot(xsec,ysec,zsec)
        self.showsection(xsec, ysec, zsec)

    def plot(self, a, b, c):
        #self.axes.cla()
        aa = float(a)
        bb = float(b)
        cc = float(c)

        line1 = self.axes.plot([aa, aa], [45, -1], [63, 63],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line2 = self.axes.plot([aa, aa], [-1, -1], [63, -1],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line3 = self.axes.plot([aa, aa], [45, 45], [63, -1],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line4 = self.axes.plot([aa, aa], [-1, 45], [-1, -1],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)

        line5 = self.axes.plot([42, -1], [bb, bb], [63, 63],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line6 = self.axes.plot([-1, -1], [bb, bb], [63, -1],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line7 = self.axes.plot([42, 42], [bb, bb], [63, -1],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line8 = self.axes.plot([-1, 42], [bb, bb], [-1, -1],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)

        line9 = self.axes.plot([42, 42], [42, -1], [cc, cc],
                               '-',
                               c='k',
                               linewidth=3,
                               zorder=20)
        line10 = self.axes.plot([42, -1], [-1, -1], [cc, cc],
                                '-',
                                c='k',
                                linewidth=3,
                                zorder=20)
        line11 = self.axes.plot([-1, 42], [42, 42], [cc, cc],
                                '-',
                                c='k',
                                linewidth=3,
                                zorder=20)
        line12 = self.axes.plot([-1, -1], [-1, 42], [cc, cc],
                                '-',
                                c='k',
                                linewidth=3,
                                zorder=20)

        self.canvas.draw()

    @jit
    def showsection(self, a, b, c):
        aa = int(a)
        bb = int(b)
        cc = int(c)

        j = 0
        k = 0
        while j < 41:
            k = 0
            while k < 62:
                if self.data[aa, j, k] < 3:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(1, 0, 0.1, 1))
                elif self.data[aa, j, k] > 3 and self.data[aa, j, k] < 4:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(1, 0.5, 0, 1))
                elif self.data[aa, j, k] > 4 and self.data[aa, j, k] < 5:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(1, 1, 0, 1))
                elif self.data[aa, j, k] > 5 and self.data[aa, j, k] < 6:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0.5, 1, 0, 1))
                elif self.data[aa, j, k] > 6 and self.data[aa, j, k] < 7:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0, 1, 1, 1))
                elif self.data[aa, j, k] > 7 and self.data[aa, j, k] < 8:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0, 0, 1, 1))
                elif self.data[aa, j, k] > 8:
                    rectangle = mpatches.Rectangle((0 + j, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0.5, 0.2, 0.9, 1))
                print(self.data[aa, j, k])
                self.axx.add_patch(rectangle)
                k = k + 1
            j = j + 1
        self.canvas.draw()

        i = 0
        k = 0
        while i < 41:
            k = 0
            while k < 62:
                if self.data[i, bb, k] < 3:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(1, 0, 0.1, 1))
                elif self.data[i, bb, k] > 3 and self.data[i, bb, k] < 4:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(1, 0.5, 0, 1))
                elif self.data[i, bb, k] > 4 and self.data[i, bb, k] < 5:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(1, 1, 0, 1))
                elif self.data[i, bb, k] > 5 and self.data[i, bb, k] < 6:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0.5, 1, 0, 1))
                elif self.data[i, bb, k] > 6 and self.data[i, bb, k] < 7:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0, 1, 1, 1))
                elif self.data[i, bb, k] > 7 and self.data[i, bb, k] < 8:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0, 0, 1, 1))
                elif self.data[i, bb, k] > 8:
                    rectangle = mpatches.Rectangle((0 + i, 0 + k),
                                                   1,
                                                   1,
                                                   color=(0.5, 0.2, 0.9, 1))
                print(self.data[i, bb, k])
                self.axy.add_patch(rectangle)
                k = k + 1
            i = i + 1
        self.canvas.draw()

        i = 0
        j = 0
        while i < 41:
            j = 0
            while j < 41:
                if self.data[i, j, cc] < 3:
                    rectangle = mpatches.Rectangle((0 + i, 0 + j),
                                                   1,
                                                   1,
                                                   color=(1, 0, 0.1, 1))
                elif self.data[i, j, cc] > 3 and self.data[i, j, cc] < 4:
                    rectangle = mpatches.Rectangle((0 + i, 0 + j),
                                                   1,
                                                   1,
                                                   color=(1, 0.5, 0, 1))
                elif self.data[i, j, cc] > 4 and self.data[i, j, cc] < 5:
                    rectangle = mpatches.Rectangle((0 + i, 0 + j),
                                                   1,
                                                   1,
                                                   color=(1, 1, 0, 1))
                elif self.data[i, j, cc] > 5 and self.data[i, j, cc] < 6:
                    rectangle = mpatches.Rectangle((0 + i, 0 + j),
                                                   1,
                                                   1,
                                                   color=(0.5, 1, 0, 1))
                elif self.data[i, j, cc] > 6 and self.data[i, j, cc] < 7:
                    rectangle = mpatches.Rectangle((0 + i, 0 + j),
                                                   1,
                                                   1,
                                                   color=(0, 1, 1, 1))
                elif self.data[i, j, cc] > 7 and self.data[i, j, cc] < 8:
                    rectangle = mpatches.Rectangle((0 + i, 0 + j),
                                                   1,
                                                   1,
                                                   color=(0, 0, 1, 1))
                elif self.data[i, j, cc] > 8:
                    rectangle = mpatches.Rectangle(
                        (0 + i, 0 + j),
                        1,
                        1,
                        color=(0.5, 0.2, 0.9, 1),
                    )
                print(self.data[i, j, cc])
                self.axz.add_patch(rectangle)
                j = j + 1
            i = i + 1
        self.canvas.draw()
Exemple #23
0
class LPlotWidget(LWidget):

    def __init__(self, parent=None):
        super(LPlotWidget, self).__init__(parent)
        self.setName(WIDGET_NAME)
        self.buildUi()
        self.dataContainer = LMyDataContainer(self)
        self.actions = LMyActions(self.dataContainer,self)
        self.updateUi()

    @LInAndOut(DEBUG & WIDGETS)
    def buildUi(self):
        self.verticalLayout = QVBoxLayout(self)
        #width, height = (14, 4)
        #width, height = figaspect(2.)
        width = 1 
        height = 1 
        dpi = 72

        self.figure = Figure(figsize=(width, height), dpi=dpi)		# <-- figs created with same geometry!
        self.figure2 = Figure(figsize=(width, height), dpi=dpi)

        #self.figure = Figure(dpi=dpi)		# <-- figs created with same geometry!
        #self.figure2 = Figure(dpi=dpi)

        #self.axe111 = self.figure2.add_axes((0,0,1,1),title="My Axe Title",xlabel='X',ylabel='Y')
        #self.axesSubplot_111 = self.figure.add_subplot(2,2,1)
        #print self.axesSubplot_111.get_position()
        #self.axesSubplot_111 = self.figure.add_subplot(2,2,2)
        #print self.axesSubplot_111.get_position()
        #self.axesSubplot_111 = self.figure.add_subplot(2,2,3)
        #self.axesSubplot_111.set_frame_on(False)
        #self.bbox = self.axesSubplot_111.get_position()
        #print self.bbox.__class__.__name__
        #print self.axesSubplot_111.get_position()
        self.axesSubplot_111 = self.figure.add_subplot(2,2,4)
        self.axesSubplot_111.plot([1,0])
        #print self.axesSubplot_111.get_position()
        #self.axesSubplot_111.set_position(self.bbox)
        #self.axesSubplot_111.set_position([0.54772727, 0.53636364, 0.9, 0.9      ])

        self.axesSubplot_111 = self.figure2.add_subplot(2,2,2)            # <-- creation in fig2
        self.axesSubplot_111 = self.figure2.add_subplot(1,1,1)            # <-- position in fig2 doesn't impact position in fig1

        print self.axesSubplot_111.__class__.__name__
        print self.axesSubplot_111.get_position()
        print self.axesSubplot_111.get_axes_locator()
        #self.bbox = self.axesSubplot_111.get_position()
        self.axesSubplot_111.grid(color='g', linestyle='-.', linewidth=1)
        self.axesSubplot_111.plot([0,1])

        #Change to the figure
        #self.axesSubplot_111.set_figure(self.figure)
        #self.figure.add_axes(self.axesSubplot_111)
        x0 = 1.0
        y0 = 1.0
        xspan = 8.0
        yspan = 8.0
        pos = [x0,y0,xspan,yspan]
        self.addAxesSubplot(self.axesSubplot_111, position=pos)

        #self.axesSubplot_111.reset_position()
        #self.axesSubplot_111.set_position(pos=pos,which='both')
        #self.axesSubplot_111.set_position(self.bbox,which='both')			# <-- as if the bbox where scalled differently
        self.figureCanvas = FigureCanvas(self.figure)	# <-- figure required
        self.verticalLayout.addWidget(self.figureCanvas)

        #FigureCanvas.setSizePolicy(self.figureCanvas, QSizePolicy.Expanding, QSizePolicy.Expanding)
        #FigureCanvas.updateGeometry(self.figureCanvas)


    @LInAndOut(DEBUG & WIDGETS)
    def updateUi(self):
        self.figure.suptitle(self.dataContainer.figureTitle)

    #----------------------------------------------------------------------
    # Interface (set)

    @LInAndOut(DEBUG & WIDGETS)
    def setOptions(self, options):
        super(LPlotWidget, self).setOptions(options)
        if options.verboseLevel is not None:
            self.setVerboseLevel(options.verboseLevel)
        if options.figureTitle is not None:
            self.setFigureTitle(options.figureTitle)
        self.updateUi()

    @LInAndOut(DEBUG & WIDGETS)
    def setVerboseLevel(self, level):
        self.dataContainer.verboseLevel = level

    #----------------------------------------------------------------------
    # Interface (get)

    #----------------------------------------------------------------------
    # QT SLOTS    

    @LInAndOut(DEBUG & WIDGETS)
    def setFigureTitle(self, title):
        self.dataContainer.figureTitle = title

    @pyqtSlot()
    def clear(self):
        for a in self.figure.get_axes():
            self.figure.delaxes(a)
        #self.axe111.clear()
        #self.figure.draw()
        self.figureCanvas.draw()

    @pyqtSlot()
    def snapshot(self, fileName = None):
        if fileName is None:
            caption = "%s - Save File" % self.name
            filter = "PNG Image (*.png);;All files (*.*)"
            fileName = QFileDialog.getSaveFileName(self.parent(), caption=caption,filter=filter )
            fileName = "%s" % fileName
        if len(fileName) > 0:
            self.figure.savefig(fileName, facecolor='w', edgecolor='w', orientation='portrait', papertype=None, format=None, transparent=False, bbox_inches=None, pad_inches=0.1)

    @pyqtSlot()
    def addAxesSubplot(self, axesSubplot, position=None, bbox=None):
        axesSubplot.set_figure(self.figure)
        self.figure.add_axes(axesSubplot)
        if position is not None:
            axesSubplot.set_position(position)
        if bbox is not None:
            axesSubplot.set_position(bbox)

    @pyqtSlot()
    def addAxesSubplots(self, axesSubplots):
        for axesSubplot in axesSubplots:
            self.addSubplot(axesSubplot)
class App:
    def __init__(self,master):

        # create toplevel window
        frame = Frame(master)
        
        frame.grid(ipadx=10,ipady=10)

        try:
            sys.argv[1]
        except:
            self.datatype = None
        else:
            self.datatype = sys.argv[1].split('--')[1]

        
        self.wdir = os.getcwd() + '/'
        self.I = pp.Image()
        self.Tool = pp.Tools()
        


        self.lb1=Label(frame, text="Nstep").grid(row=0,column=0)
        
        
        
        self.enstep = Entry(frame,width=8)
        self.enstep.grid(row=0,column=1)
        self.enstep.insert(0, "0")

        self.LoadedNstep = StringVar()
        self.PresentTime = StringVar()

        self.myData = self.loaddata()
        self.varkeys = self.myData.get_varinfo(self.datatype)['allvars']
        self.grid_dict= self.myData.grid()
    

        if self.grid_dict["n3"] != 1:
            self.Geom = '3D'
        elif self.grid_dict["n3"] == 1 and self.grid_dict["n2"] != 1:
            self.Geom = '2D'
        else:
            self.Geom = '1D'
            
        

        self.ldatabutton=Button(frame,text="Load data",command=self.loaddata)
        self.ldatabutton.grid(row=0,column=2)

############### MARK THE CUTS #################################

        self.ex1 = Entry(frame,width=5)
        self.ex1.grid(row=2,column=0)
        self.ex1.insert(0, "x1")

        self.ex2 = Entry(frame,width=5)
        self.ex2.grid(row=2,column=1)
        self.ex2.insert(0, "x2")
        
        self.ex3 = Entry(frame,width=5)
        self.ex3.grid(row=2,column=2)
        self.ex3.insert(0, "x3")

        if self.Geom == '2D':
            self.ex3.config(state='disabled')

        if self.Geom == '1D':
            self.ex3.config(state='disabled')
            self.ex2.config(state='disabled')
            self.ex1.config(state='disabled')
        

        # place a graph somewhere here
        self.f = Figure(figsize=(7,7), dpi=100)
        self.a = self.f.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.f, master=root)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(row=0,column=3,columnspan=10,rowspan=10,sticky=E)

        #self.toolbar = NavigationToolbar2TkAgg(self.canvas,tl)
        #self.toolbar.update()
        #self.canvas._tkcanvas.grid(row=60,column=15,sticky=E)

        self.v = StringVar()
        self.v.set("None")

################ VARIABLES TO PLOT #################################
        
        for j in range(len(self.varkeys)):
            self.ldata = Radiobutton(frame,text=self.varkeys[j],variable=self.v,value=self.varkeys[j],command=self.getmyvar)
            self.ldata.grid(row=3+j,column=0,sticky=W)
        

################ SLICES CHOICE #################################
            
        self.slvar = StringVar()
        self.slvar.set("Choose Slice")
        if self.Geom == '3D' :
            SliceList = ("Along x1","Along x2","Along x3","Along x1-x2","Along x2-x3","Along x3-x1")
        elif self.Geom == '2D' :
            SliceList = ("Along x1", "Along x2", "Along x1-x2")
        else:
            SliceList = ()

        for j in range(len(SliceList)):
            self.sldata = Radiobutton(frame,text=SliceList[j],variable=self.slvar,value=SliceList[j],command=self.setslice)
            self.sldata.grid(row=3+j,column=1,sticky=W)

############### PLOT PROPERTIES #################################
            
        self.logvar = IntVar()
        self.chkb = Checkbutton(frame,text="Log  ",variable=self.logvar,onvalue=1,offvalue=0,command=self.logchkcall)
        self.chkb.grid(row=3,column=2,sticky=W)#(row=15,column=0,sticky=W)

        self.polarvar = IntVar()
        self.polchkb = Checkbutton(frame,text="Polar",variable=self.polarvar,onvalue=1,offvalue=0,command=self.polchkcall)
        self.polchkb.grid(row=4,column=2,sticky=W)#(row=15,column=1)
        if self.Geom == '1D':
            self.polchkb.config(state='disabled')
            self.polarvar.set(0)

        self.preaspect = IntVar()
        self.aspectb = Checkbutton(frame,text="Aspect",variable=self.preaspect,onvalue=1,offvalue=0,command=self.aspchkcall)
        self.aspectb.grid(row=5,column=2,sticky=W)#(row=15,column=2)
        if self.Geom == '1D':
            self.aspectb.config(state='disabled')

        

        

        
################ X and Y LABELS #################################
        
        self.lb2=Label(frame,text="Labels").grid(row=22,column=0)
    
        self.xlb = Entry(frame,width=15)
        self.xlb.grid(row=22,column=1)
        self.xlb.insert(0, "xlabel")

        self.ylb = Entry(frame,width=15)
        self.ylb.grid(row=22,column=2)
        self.ylb.insert(0, "ylabel")

############### X and Y RANGE#######################

        self.lb2a=Label(frame,text="XRange").grid(row=24,column=0)
        self.lb2b=Label(frame,text="YRange").grid(row=26,column=0)
        self.lb2c=Label(frame,text="VarRange").grid(row=28,column=0)
        
        self.xrmin = Entry(frame,width=15)
        self.xrmin.grid(row=24,column=1)
        self.xrmin.insert(0,'')
        self.xrmax = Entry(frame,width=15)
        self.xrmax.grid(row=24,column=2)
        self.xrmax.insert(0,'')
        
        self.yrmin = Entry(frame,width=15)
        self.yrmin.grid(row=26,column=1)
        self.yrmin.insert(0,'')
        self.yrmax = Entry(frame,width=15)
        self.yrmax.grid(row=26,column=2)
        self.yrmax.insert(0,'')

        self.varmin = Entry(frame,width=15)
        self.varmin.grid(row=28,column=1)
        self.varmin.insert(0,'')
        self.varmax = Entry(frame,width=15)
        self.varmax.grid(row=28,column=2)
        self.varmax.insert(0,'')
        if self.Geom == '1D':
            self.yrmin.config(state='disabled')
            self.yrmax.config(state='disabled')


################ CONTOURS #################################

        self.lb3=Label(frame,text="Contours").grid(row=16,column=0)
        
        self.contvar = IntVar()
        self.chkb = Checkbutton(frame,text="Contour",variable=self.contvar,onvalue=1,offvalue=0,command=self.contchkcall)
        self.chkb.grid(row=6,column=2,sticky=W)#(row=16,column=0,sticky=W)

        self.plcont = StringVar()
        self.contkeys = ["None"]
        if "bx1" in self.varkeys:
            for item in self.varkeys:
                self.contkeys.append(item)
            self.contkeys.append("x1*bx3")
            if "Ax3" in self.varkeys:
                self.contkeys.append("x1*Ax3")
        else:
            for item in self.varkeys:
                self.contkeys.append(item)        
        self.plcont.set("None")
        self.contmenu = OptionMenu(frame, self.plcont,*self.contkeys)
        self.contmenu.grid(row=16,column=1)

        self.xlevb = Entry(frame,width=15)
        self.xlevb.grid(row=16,column=2,sticky=W)
        self.xlevb.insert(0, "Levels")
        self.xlevb.config(state='disabled')
        self.contmenu.config(state='disabled')

        if self.Geom == '1D':
            self.chkb.config(state = 'disabled')
        
################ ARROWS #################################

        self.lb4=Label(frame,text="Arrows").grid(row=19,column=0)

        self.arrowvar = IntVar()
        self.arrowchkb = Checkbutton(frame,text="Arrows",variable=self.arrowvar,onvalue=1,offvalue=0,command=self.arrchkcall)
        self.arrowchkb.grid(row=7,column=2,sticky=W)#(row=16,column=0,sticky=W)

        self.arrspb = Entry(frame,width=15)
        self.arrspb.grid(row=19,column=2,sticky=W)
        self.arrspb.insert(0, "20")

    
        self.plarr = StringVar()
        self.arrkeys = ["None"]
        self.arrkeys.append("Vp")
        self.arrkeys.append("Vp_norm")
        if "bx1" in self.varkeys:
            self.arrkeys.append("Bp")
            self.arrkeys.append("Bp_norm")
        self.plarr.set("None")
        self.arrmenu = OptionMenu(frame,self.plarr,*self.arrkeys)
        self.arrmenu.grid(row=19,column=1)
        self.arrmenu.config(state='disabled')
        self.arrspb.config(state='disabled')

        if self.Geom == '1D':
            self.arrowchkb.config(state = 'disabled')
        

                
################ VARIOUS PLOTTING BUTTONS #################################

        self.pltbutton=Button(frame,text="Plot",command=self.plotfinal)
        self.pltbutton.grid(row=36,column=0)
        if self.Geom == '1D':
            self.pltbutton.config(state='active')
        else:
            self.pltbutton.config(state='disabled')

        self.surfbutton=Button(frame,text="Surface",command=self.plotsurface)
        self.surfbutton.grid(row=36,column=1)
        self.surfbutton.config(state='disabled')
        #if self.Geom == '1D':
        #    self.surfbutton.config(state='disabled')
        
        
        self.clrbutton=Button(frame,text="Clear",command=self.plotclear)
        self.clrbutton.grid(row=36,column=2)

################ INFORMATION #################################

        self.lbinf0 =  Label(frame,text="Information",font=("Times",12,"bold"))
        self.lbinf0.grid(row=47,column=0,sticky=W,columnspan=3)

        self.lbinf1a = Label(frame,text="Dir :",font=("Times",10,"bold")).grid(row=49,column=0,sticky=W,columnspan=3)
        self.lbinf1 =  Label(frame,text=self.wdir).grid(row=50,column=0,sticky=W,columnspan=3)
        self.lbinf2a = Label(frame,text="Domain :",font=("Times",10,"bold")).grid(row=51,column=0,sticky=W,columnspan=3)
        self.lbinf2 = Label(frame,text="n1 x n2 x n3 =  %d x %d x %d " % (self.grid_dict.get('n1'),self.grid_dict.get('n2'),self.grid_dict.get('n3'))).grid(row=52,column=0,sticky=W,columnspan=3)
        self.lbinf3a = Label(frame,text="Time Status",font=("Times",10,"bold")).grid(row=53,column=0,sticky=W,columnspan=3)
        self.lbinf4 = Label(frame,text="Nlast = %d"% (pp.nlast_info(datatype=self.datatype).get('nlast'))).grid(row=54,column=0,sticky=W,columnspan=3)
        self.lbinf5 = Label(frame,textvariable = self.LoadedNstep).grid(row=55,column=0,sticky=W,columnspan=3)
        self.lbinf6 = Label(frame,textvariable = self.PresentTime).grid(row=56,column=0,sticky=W,columnspan=3)
    

################ VARIOUS FUNCTIONS #################################
        
    
                                
    def loaddata(self):
        try:
            int(self.enstep.get().strip().split()[0])
        except (ValueError, IndexError):
            print "Specify the proper value of Nstep"
        else:
            mynstep=int(self.enstep.get())
            self.D = pp.pload(mynstep,w_dir=self.wdir,datatype=self.datatype)
            self.LoadedNstep.set("Loaded Nstep = "+self.enstep.get())
            self.PresentTime.set("Present Time = "+str(self.D.time_info(self.datatype)['time'])+" [cu]")
            return self.D


    def getmyvar(self):
        try:
            self.v.get() != "None"
        except KeyError:
            print "Specify the variable to plot"
        else:
            self.myvar=self.v.get()
        
    def logchkcall(self):
        self.logchk = self.logvar.get()

    def contchkcall(self):
        self.contchk = self.contvar.get()
        if self.contchk == 1:
            self.contmenu.config(state='normal')
            self.xlevb.config(state='normal')
        else:
            self.contmenu.config(state='disabled')
            self.xlevb.config(state='disabled')

    def arrchkcall(self):
        self.arrchk = self.arrowvar.get()
        if self.arrchk == 1:
            self.arrmenu.config(state='normal')
            self.arrspb.config(state='normal')
        else:
            self.arrmenu.config(state='disabled')
            self.arrspb.config(state='disabled')

    def aspchkcall(self):
        self.aspchk=self.preaspect.get()

    def polchkcall(self):
        self.polchk = self.polarvar.get()
        
    def setslice(self):
        self.slicename=self.slvar.get()
        if self.slicename == "Along x1" or self.slicename == "Along x2" or self.slicename == "Along x3":
            self.surfbutton.config(state='disabled')
            self.arrowchkb.config(state = 'disabled')
            self.arrowvar.set(0)
            self.chkb.config(state = 'disabled')
            self.contvar.set(0)
            self.pltbutton.config(state='active')
            self.polchkb.config(state='disabled')
            self.polarvar.set(0)
        else:
            self.pltbutton.config(state='disabled')
            self.arrowchkb.config(state = 'normal')
            self.chkb.config(state = 'normal')
            self.surfbutton.config(state='active')
            self.polchkb.config(state='normal')
        
        if self.slicename == "Along x2-x3":
            self.polchkb.config(state='disabled')
            self.polarvar.set(0)
            
        
    
    def plotclear(self):
        self.a.clear()
       
        
        if len(self.f.axes)>1:
            self.f.delaxes(self.f.axes[1])
            self.f.subplots_adjust(right=0.90)

        self.canvas.show()

    def plotfinal(self):
        if self.getplotvar() == True:
            self.a.axis([self.getxaxisrange()[0],self.getxaxisrange()[1],self.getvarrange()[0],self.getvarrange()[1]])
            self.a.plot(self.x,self.var)
            self.a.set_aspect('auto')
        self.a.set_xlabel(self.xlb.get())
        self.a.set_ylabel(self.ylb.get())
        self.canvas.show()

    def plotsurface(self):
        tdum = time.time()
        self.plotclear()
        
        if self.preaspect.get() == 1:
            self.a.set_aspect('equal')
        else:
            self.a.set_aspect('auto')

        
        if self.polarvar.get() == 1:
            if self.drawpolar() == True:
                self.a.axis([self.getxaxisrange()[0],self.getxaxisrange()[1],self.getyaxisrange()[0],self.getyaxisrange()[1]])
                self.image = self.a.imshow(self.SphData[self.myvar], origin='lower',extent=self.extent, interpolation='nearest',cmap="jet", vmin=self.getvarrange()[0],vmax=self.getvarrange()[1])
                self.f.colorbar(self.image)
        else:
            if self.getsurfvar() == True:
                self.a.axis([self.getxaxisrange()[0],self.getxaxisrange()[1],self.getyaxisrange()[0],self.getyaxisrange()[1]])
                self.image=self.a.pcolormesh(self.x,self.y,self.var,cmap='jet',vmin=self.getvarrange()[0],vmax=self.getvarrange()[1])
                self.f.colorbar(self.image)
        

        if self.contvar.get() == 1:
            try:
                self.plcont.get() != "None"
            except KeyError:
                print "Specify the variable for Contour"
            else:
                self.drawcontour()
                self.contlevlist=[]
                self.contlevstr = string.split(self.xlevb.get(),',')
                try:
                    if self.contlevstr[0] == 'log':
                        self.flevel = self.contlevstr[1]
                        self.varcont = log10(self.varcont)
                    else:
                        self.flevel = self.contlevstr[0]
                    
                    float(self.flevel)
                    self.contlevlist = [float(self.flevel)]
                    
                except:
                    self.contlevlist = 5
                else:
                    for j in range(1,len(self.contlevstr)):
                        self.contlevlist.append(float(self.contlevstr[j]))


                self.cs1 = self.a.contour(self.xcont,self.ycont,self.varcont,self.contlevlist,colors="w")
                self.a.clabel(self.cs1,inline=True)
        

        if self.arrowvar.get() == 1:
            try:
                self.plarr.get() != "None"
            except KeyError:
                print "Specify the variable for plotting the arrow"
            else:
                self.drawarrow()
                self.a.quiver(self.xcong, self.ycong, self.xveccong, self.yveccong,color='w')
        
        self.a.set_xlabel(self.xlb.get())
        self.a.set_ylabel(self.ylb.get())
        self.canvas.show()
        


    def getvarrange(self):
        try:
            float(self.varmin.get())
        except:
            if self.polarvar.get() != 1:
                self.varminval = min(self.var)
            else:
                self.varminval = min(self.SphData[self.myvar][self.isnotnan].flat)#self.minPl
        else:
            self.varminval = float(self.varmin.get())

        try:
            float(self.varmax.get())
        except:
            if self.polarvar.get() != 1:
                self.varmaxval = max(self.var)
            else:
                self.varmaxval = max(self.SphData[self.myvar][self.isnotnan].flat)#self.maxPl
        else:
            self.varmaxval = float(self.varmax.get())

        return [self.varminval,self.varmaxval]
        

    def getxaxisrange(self):
        try:
            float(self.xrmin.get())
        except:
            if self.polarvar.get() != 1:
                self.xminval = min(self.x)
            else:
                self.xminval = min(self.R.flat)
        else:
            self.xminval = float(self.xrmin.get())

        try:
            float(self.xrmax.get())
        except:
            if self.polarvar.get() != 1:
                self.xmaxval = max(self.x)
            else:
                self.xmaxval = max(self.R.flat)
        else:
            self.xmaxval = float(self.xrmax.get())

        return [self.xminval,self.xmaxval]

    def getyaxisrange(self):
        try:
            float(self.yrmin.get())
        except:
            if self.polarvar.get() != 1:
                self.yminval = min(self.y)
            else:
                self.yminval = min(self.Z.flat)
        else:
            self.yminval = float(self.yrmin.get())

        try:
            float(self.yrmax.get())
        except:
            if self.polarvar.get() != 1:
                self.ymaxval = max(self.y)
            else:
                self.ymaxval = max(self.Z.flat)
        else:
            self.ymaxval = float(self.yrmax.get())

        return [self.yminval,self.ymaxval]


    def getplotvar(self):
        self.sucess = False
        if self.logvar.get() == 1:
            self.var = log10(self.D.__getattribute__(self.myvar))
        else:
            self.var = self.D.__getattribute__(self.myvar)

        if self.Geom == '1D':
            self.x = self.D.x1
            self.sucess = True
        else:
            if self.slicename == "Along x1":
                self.x = self.D.x1
                if self.grid_dict["n3"] == 1:
                    try:
                        int(self.ex2.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x2 cut"
                    else:
                        self.var = self.var[:,int(self.ex2.get())]
                        self.sucess = True
                else:
                    try:
                        int(self.ex2.get().strip().split()[0])
                        int(self.ex3.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x2 or x3 cut"
                    else:
                        self.var = self.var[:,int(self.ex2.get()),int(self.ex3.get())]
                        self.sucess = True
            
            elif self.slicename == "Along x2":
                self.x = self.D.x2
                if self.grid_dict["n3"] == 1:
                    try:
                        int(self.ex1.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x1 cut"
                    else:
                        self.var = self.var[int(self.ex1.get()),:]
                        self.sucess = True
                else:
                    try:
                        int(self.ex1.get().strip().split()[0])
                        int(self.ex3.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x1 or x3 cut"
                    else:
                        self.var = self.var[int(self.ex1.get()),:,int(self.ex3.get())]
                        self.sucess = True

            else:
                self.x = self.D.x3
                try:
                    int(self.ex1.get().strip().split()[0])
                    int(self.ex2.get().strip().split()[0])
                except (ValueError, IndexError):
                    print "Specify the value of x1 or x2 cut"
                else:
                    self.var = self.var[int(self.ex1.get()),int(self.ex2.get()),:]
                    self.sucess = True

        return self.sucess

    def getsurfvar(self):
        self.sucess = False
        if self.logvar.get() == 1:
            self.var = log10(self.D.__getattribute__(self.myvar))
        else:
            self.var = self.D.__getattribute__(self.myvar)
        
        if self.slicename == "Along x1-x2":
            self.x = self.D.x1
            self.y = self.D.x2
            xmineed = (abs(self.x-self.getxaxisrange()[0])).argmin()
            xmaneed = (abs(self.x-self.getxaxisrange()[1])).argmin()
            ymineed = (abs(self.y-self.getyaxisrange()[0])).argmin()
            ymaneed = (abs(self.y-self.getyaxisrange()[1])).argmin()
            self.x = self.x[xmineed:xmaneed]
            self.y = self.y[ymineed:ymaneed]
            if self.grid_dict["n3"] == 1:
                self.var = self.var[xmineed:xmaneed,ymineed:ymaneed].T
                self.sucess = True
            else:
                try:
                    int(self.ex3.get().strip().split()[0])
                except (ValueError, IndexError):
                    print "Specify the value of x3 cut"
                else:
                    self.var = self.var[xmineed:xmaneed,ymineed:ymaneed,int(self.ex3.get())].T
                    self.sucess = True
                
        elif self.slicename == "Along x2-x3":
            self.x = self.D.x2
            self.y = self.D.x3
            xmineed = (abs(self.x-self.getxaxisrange()[0])).argmin()
            xmaneed = (abs(self.x-self.getxaxisrange()[1])).argmin()
            ymineed = (abs(self.y-self.getyaxisrange()[0])).argmin()
            ymaneed = (abs(self.y-self.getyaxisrange()[1])).argmin()
            self.x = self.x[xmineed:xmaneed]
            self.y = self.y[ymineed:ymaneed]
            try:
                int(self.ex1.get().strip().split()[0])
            except (ValueError, IndexError):
                print "Specify the value of x1 cut"
            else:
                self.var = self.var[int(self.ex1.get()),xmineed:xmaneed,ymineed:ymaneed].T
                self.sucess = True
        else:
            self.x = self.D.x1
            self.y = self.D.x3
            xmineed = (abs(self.x-self.getxaxisrange()[0])).argmin()
            xmaneed = (abs(self.x-self.getxaxisrange()[1])).argmin()
            ymineed = (abs(self.y-self.getyaxisrange()[0])).argmin()
            ymaneed = (abs(self.y-self.getyaxisrange()[1])).argmin()
            self.x = self.x[xmineed:xmaneed]
            self.y = self.y[ymineed:ymaneed]
            try:
                int(self.ex2.get().strip().split()[0])
            except (ValueError, IndexError):
                print "Specify the value of x2 cut"
            else:
                self.var = self.var[xmineed:xmaneed,int(self.ex2.get()),ymineed:ymaneed].T
                self.sucess = True
        
        return self.sucess

    def drawpolar(self):
        self.sucess = False
        if self.slicename == "Along x1-x2":
            if self.grid_dict["n3"] == 1:
                self.R,self.Z,self.SphData = self.I.getSphData(self.D,w_dir=self.wdir,datatype=self.datatype, rphi=False)
                self.sucess = True
            else:
                try:
                    int(self.ex3.get().strip().split()[0])
                except (ValueError, IndexError):
                    print "Specify the value of x3 cut"
                else:
                    self.R,self.Z,self.SphData = self.I.getSphData(self.D,w_dir=self.wdir,datatype=self.datatype, rphi=False,x3cut=int(self.ex3.get()))
                    self.sucess = True

        if self.slicename == "Along x3-x1":
            try:
                int(self.ex2.get().strip().split()[0])
            except (ValueError, IndexError):
                print "Specify the value of x2 cut"
            else:
                self.R,self.Z,self.SphData = self.I.getSphData(self.D,w_dir=self.wdir,datatype=self.datatype, rphi=True, x2cut=int(self.ex2.get()))
                self.sucess = True

        if self.sucess == True:
            self.extent=(min(self.R.flat),max(self.R.flat),min(self.Z.flat),max(self.Z.flat))
            self.dRR=max(self.R.flat)-min(self.R.flat)
            self.dZZ=max(self.Z.flat)-min(self.Z.flat)

            self.isnotnan=-isnan(self.SphData[self.myvar])
            self.maxPl=max(self.SphData[self.myvar][self.isnotnan].flat)
            self.minPl=min(self.SphData[self.myvar][self.isnotnan].flat)
            self.normrange=False
            if self.minPl<0:
                self.normrange=True
            if self.maxPl>-self.minPl:
                self.minPl=-self.maxPl
            else:
                self.maxPl=-self.minPl	  
            if (self.normrange and self.myvar !='rho' and self.myvar !='prs'):
                self.SphData[self.myvar][-1][-1]=self.maxPl
                self.SphData[self.myvar][-1][-2]=self.minPl
            if self.logvar.get() == 1:
                self.SphData[self.myvar] = log10(self.SphData[self.myvar])

        return self.sucess


    def drawcontour(self):
        if self.polarvar.get() != 1:
            if self.slicename == "Along x1-x2":
                self.xcont = self.D.x1
                self.ycont = self.D.x2
                self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T,self.D.x2.T)
                if self.grid_dict["n3"] == 1:
                    if self.plcont.get() == 'x1*Ax3':
			self.varcont = self.Xmesh*(self.D.Ax3.T)
                    elif self.plcont.get() == 'x1*bx3':
			self.varcont = self.Xmesh*(self.D.bx3.T)
                    else:
                        self.varcont = self.D.__getattribute__(self.plcont.get())[:,:].T              
                else:
                    if self.plcont.get() == 'x1*Ax3':
			self.varcont = self.Xmesh*(self.D.Ax3[:,:,int(self.ex3.get())].T)
                    elif self.plcont.get() == 'x1*bx3':
			self.varcont = self.Xmesh*(self.D.bx3[:,:,int(self.ex3.get())].T)
                    else:
                        self.varcont = self.D.__getattribute__(self.plcont.get())[:,:,int(self.ex3.get())].T
                        
            elif self.slicename == "Along x2-x3":
                self.xcont = self.D.x2
                self.ycont = self.D.x3
                self.varcont = self.D.__getattribute__(self.plcont.get())[int(self.ex1.get()),:,:].T
            else:
                self.xcont = self.D.x1
                self.ycont = self.D.x3
                self.varcont = self.D.__getattribute__(self.plcont.get())[:,int(self.ex2.get()),:].T
        else:
            self.xcont = self.R
            self.ycont = self.Z
            if self.plcont.get() == 'x1*Ax3':
                self.varcont = self.R*(self.SphData['Ax3'])
            elif self.plcont.get() == 'x1*bx3':
                self.varcont = self.R*(self.SphData['bx3'])
            else:
                if self.logvar.get() == 1 and self.plcont.get() == self.myvar:
                    self.varcont = 10**(self.SphData[self.plcont.get()])
                else:
                    self.varcont = self.SphData[self.plcont.get()]

    def drawarrow(self):
        if self.polarvar.get() != 1:
            if self.slicename == "Along x1-x2":
                self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T,self.D.x2.T)
                self.xcong = self.Tool.congrid(self.Xmesh,2*(int(self.arrspb.get()),),method='linear')
                self.ycong = self.Tool.congrid(self.Ymesh,2*(int(self.arrspb.get()),),method='linear')
                if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm':
                    if self.grid_dict["n3"] == 1:
                        self.vel1 = self.D.vx1[:,:].T
                        self.vel2 = self.D.vx2[:,:].T
                    else:
                        self.vel1 = self.D.vx1[:,:,int(self.ex3.get())].T
                        self.vel2 = self.D.vx2[:,:,int(self.ex3.get())].T
                        
                    self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear')
                    self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Vp_norm':
                        self.xveccong = self.xveccong/self.normVp
                        self.yveccong = self.yveccong/self.normVp
                if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm':
                    if self.grid_dict["n3"] == 1:
                        self.mag1 = self.D.bx1[:,:].T
                        self.mag2 = self.D.bx2[:,:].T
                    else:
                        self.mag1 = self.D.bx1[:,:,int(self.ex3.get())].T
                        self.mag2 = self.D.bx2[:,:,int(self.ex3.get())].T
                        
                    self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear')
                    self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Bp_norm':
                        self.xveccong = self.xveccong/self.normVp
                        self.yveccong = self.yveccong/self.normVp
                
            elif self.slicename == "Along x2-x3":
                self.Xmesh, self.Ymesh = meshgrid(self.D.x2.T,self.D.x3.T)
                self.xcong = self.Tool.congrid(self.Xmesh,2*(int(self.arrspb.get()),),method='linear')
                self.ycong = self.Tool.congrid(self.Ymesh,2*(int(self.arrspb.get()),),method='linear')
                if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm':
                    self.vel1 = self.D.vx2[int(self.ex1.get()),:,:].T
                    self.vel2 = self.D.vx3[int(self.ex1.get()),:,:].T
                    self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear')
                    self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Vp_norm':
                        self.xveccong = self.xveccong/self.normVp
                        self.yveccong = self.yveccong/self.normVp
                if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm':
                    self.mag1 = self.D.bx2[int(self.ex1.get()),:,:].T
                    self.mag2 = self.D.bx3[int(self.ex1.get()),:,:].T
                    self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear')
                    self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Bp_norm':
                        self.xveccong = self.xveccong/self.normVp
                        self.yveccong = self.yveccong/self.normVp
            else:
                self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T,self.D.x3.T)
                self.xcong = self.Tool.congrid(self.Xmesh,2*(int(self.arrspb.get()),),method='linear')
                self.ycong = self.Tool.congrid(self.Ymesh,2*(int(self.arrspb.get()),),method='linear')
                if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm':
                    self.vel1 = self.D.vx1[:,int(self.ex2.get()),:].T
                    self.vel2 = self.D.vx3[:,int(self.ex2.get()),:].T
                    self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear')
                    self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Vp_norm':
                        self.xveccong = self.xveccong/self.normVp
                        self.yveccong = self.yveccong/self.normVp
                if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm':
                    self.mag1 = self.D.bx1[:,int(self.ex2.get()),:].T
                    self.mag2 = self.D.bx3[:,int(self.ex2.get()),:].T
                    self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear')
                    self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Bp_norm':
                        self.xveccong = self.xveccong/self.normVp
                        self.yveccong = self.yveccong/self.normVp
        else:
            self.xcong = self.Tool.congrid(self.R,2*(int(self.arrspb.get()),),method='linear')
            self.ycong = self.Tool.congrid(self.Z,2*(int(self.arrspb.get()),),method='linear')
            if self.plarr.get() == 'Vp' or self.plarr.get() =='Vp_norm':
                if self.slicename == "Along x1-x2":
                    self.vel1 = self.SphData['v1c']
                    self.vel2 = self.SphData['v2c']
                else:
                    self.vel1 = self.SphData['v1c']
                    self.vel2 = self.SphData['v3c']
                
                self.xveccong = self.Tool.congrid(self.vel1,2*(int(self.arrspb.get()),),method='linear')
                self.yveccong = self.Tool.congrid(self.vel2,2*(int(self.arrspb.get()),),method='linear')
                self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                if self.plarr.get() == 'Vp_norm':
                    self.xveccong = self.xveccong/self.normVp
                    self.yveccong = self.yveccong/self.normVp
            if self.plarr.get() == 'Bp' or self.plarr.get() =='Bp_norm':
                
                if self.slicename == "Along x1-x2":
                    self.mag1 = self.SphData['b1c']
                    self.mag2 = self.SphData['b2c']
                else:
                    self.mag1 = self.SphData['b1c']
                    self.mag2 = self.SphData['b3c']
                
                self.xveccong = self.Tool.congrid(self.mag1,2*(int(self.arrspb.get()),),method='linear')
                self.yveccong = self.Tool.congrid(self.mag2,2*(int(self.arrspb.get()),),method='linear')
                self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                if self.plarr.get() == 'Bp_norm':
                    self.xveccong = self.xveccong/self.normVp
                    self.yveccong = self.yveccong/self.normVp
        
    def epssave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.eps')
    def pngsave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.png')
    def pdfsave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.pdf')
    def jpgsave(self):
        self.f.savefig(self.myvar+'_'+self.enstep.get()+'.jpg')
class MplGraphQt5Widget(QWidget):
    def __init__(self, parent=None):
        super(MplGraphQt5Widget, self).__init__(parent)

        self.width = 3
        self.height = 3
        self.dpi = 100

        self._dataY = np.array([])
        self._dataX = np.array([])

        self._spCols = 1
        self._spRows = 1
        self.all_sp_axes = []
        self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
        self.all_sp_axes.append(self.fig.add_subplot(self._spCols, self._spRows, 1))
        self.fig.set_frameon(False)
        self.fig.set_tight_layout(True)

        self.canvas = Canvas(self.fig)

        self._navBarOn = False
        self.mpl_toolbar = NavigationToolbar(self.canvas, parent)
        self.mpl_toolbar.dynamic_update()

        self.canvas.mpl_connect('key_press_event', self.on_key_press)
        self.canvas.mpl_connect('button_press_event', self.on_button_press)
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
        self.canvas.setFocusPolicy(Qt.ClickFocus)
        self.canvas.setFocus()

        self.canvas.setParent(parent)
        self.canvas.clearMask()
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.canvas.updateGeometry()

        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        if not self._navBarOn:
            self.mpl_toolbar.hide()
        self.setLayout(vbox)



    def get_icon(name):
        """Return Matplotlib icon *name*"""
        return QIcon(osp.join(rcParams['datapath'], 'images', name))


    key_pressed = pyqtSignal(object, name='keyPressed')

    def on_key_press(self, event):
        self.key_pressed.emit(event)
        key_press_handler(event, self.canvas, self.mpl_toolbar)

    button_pressed = pyqtSignal(object, name='buttonPressed')

    def on_button_press(self, event):
        self.button_pressed.emit(event)
        key_press_handler(event, self.canvas, self.mpl_toolbar)

    mouse_move = pyqtSignal(object, name='mouseMoved')

    def on_mouse_move(self, event):
        self.mouse_move.emit(event)
        key_press_handler(event, self.canvas, self.mpl_toolbar)


    def generateNewAxes(self):
        for ax in self.all_sp_axes:
            self.fig.delaxes(ax)
        self.all_sp_axes = []
        numOfAxes = (self._spRows*self._spCols)+1
        for i in np.arange(1,numOfAxes):
            self.all_sp_axes.append(self.fig.add_subplot(self._spRows, self._spCols, i))
        self.canvas.setGeometry(100, 100, 300, 300)  #Used to update the new number of axes
        self.canvas.updateGeometry()  #This will bring the size of the canvas back to the original (defined by the vbox)

    spRowsChanged = pyqtSignal(int)

    def getspRows(self):
        return self._spRows

    @pyqtSlot(int)
    def setspRows(self, spRows):
        self._spRows = spRows
        self.generateNewAxes()
        self.spRowsChanged.emit(spRows)

    def resetspRows(self):
        self.setspRows(1)

    spRows = pyqtProperty(int, getspRows, setspRows, resetspRows)

    spColsChanged = pyqtSignal(int)

    def getspCols(self):
        return self._spCols

    @pyqtSlot(int)
    def setspCols(self, spCols):
        self._spCols = spCols
        self.generateNewAxes()
        self.spRowsChanged.emit(spCols)

    def resetspCols(self):
        self.setspCols(1)

    spCols = pyqtProperty(int, getspCols, setspCols, resetspCols)

    dataChanged = pyqtSignal(bool)

    def get_Y_data(self):
        return self._dataY

    @pyqtSlot(int)
    def set_Y_data(self, y_data):
        self._dataY = y_data
        self.dataChanged.emit(True)


    def plot(self, on_axes=0):
        if np.size(self._dataX) == 0:
            self.all_sp_axes[on_axes].plot(self._dataY)
        else:
            self.all_sp_axes[on_axes].plot(self._dataX, self._dataY)

    def getNavBarOn(self):
        return self._navBarOn

    def setNavBarOn(self, navBarOn):
        self._navBarOn = navBarOn
        if not navBarOn:
            self.mpl_toolbar.hide()
        else:
            self.mpl_toolbar.show()

    def resetNavBarOn(self):
        self._navBarOn = True

    navBarOn = pyqtProperty(bool, getNavBarOn, setNavBarOn, resetNavBarOn)

    @pyqtSlot(bool)
    def set_autoscale(self, autoscale):
        for axis in self.all_sp_axes:
            axis.set_autoscale(autoscale)
Exemple #26
0
class Qt4MplCanvas(FigureCanvas):
    """  A customized Qt widget for matplotlib figure.
    It can be used to replace GraphicsView of QtGui
    """
    def __init__(self, parent):
        """  Initialization
        """
        # from mpl_toolkits.axes_grid1 import host_subplot
        # import mpl_toolkits.axisartist as AA
        # import matplotlib.pyplot as plt

        # Instantiating matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')

        if True:
            self.axes = self.fig.add_subplot(111) # return: matplotlib.axes.AxesSubplot
            self.axes2 = None
        else:
            self.axes = self.fig.add_host_subplot(111)

        # Initialize parent class and set parent
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        # Variables to manage all lines/subplot
        self._lineDict = {}
        self._lineIndex = 0

        # legend and color bar
        self._colorBar = None

        return

    def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label="", x_label=None, y_label=None,
                    marker=None, line_style=None, line_width=1):
        """

        :param vec_x: numpy array X
        :param vec_y: numpy array Y
        :param y_err:
        :param color:
        :param label:
        :param x_label:
        :param y_label:
        :param marker:
        :param line_style:
        :param line_width:
        :return: new key
        """
        # Check input
        if isinstance(vec_x, np.ndarray) is False or isinstance(vec_y, np.ndarray) is False:
            raise NotImplementedError('Input vec_x or vec_y for addPlot() must be numpy.array.')
        plot_error = y_err is not None
        if plot_error is True:
            if isinstance(y_err, np.ndarray) is False:
                raise NotImplementedError('Input y_err must be either None or numpy.array.')

        if len(vec_x) != len(vec_y):
            raise NotImplementedError('Input vec_x and vec_y must have same size.')
        if plot_error is True and len(y_err) != len(vec_x):
            raise NotImplementedError('Input vec_x, vec_y and y_error must have same size.')

        # Hold previous data
        self.axes.hold(True)

        # process inputs and defaults
        if color is None:
            color = (0,1,0,1)
        if marker is None:
            marker = 'o'
        if line_style is None:
            line_style = '-'

        # color must be RGBA (4-tuple)
        if plot_error is False:
            print "[DB] line_style = ", line_style, "line_width = ", line_width, "marker = ", marker, "color = ", color
            r = self.axes.plot(vec_x, vec_y, color=color, marker=marker, linestyle=line_style,
                               label=label, linewidth=line_width)
            # return: list of matplotlib.lines.Line2D object
        else:
            r = self.axes.errorbar(vec_x, vec_y, yerr=y_err, color=color, marker=marker, linestyle=line_style,
                                   label=label, linewidth=line_width)

        self.axes.set_aspect('auto')

        # set x-axis and y-axis label
        if x_label is not None:
            self.axes.set_xlabel(x_label, fontsize=20)
        if y_label is not None:
            self.axes.set_ylabel(y_label, fontsize=20)

        # set/update legend
        self._setupLegend()

        # Register
        line_key = self._lineIndex
        if len(r) == 1:
            self._lineDict[line_key] = r[0]
            self._lineIndex += 1
        else:
            print "Impoooooooooooooooosible!  Return from plot is a %d-tuple. " % (len(r))

        # Flush/commit
        self.draw()

        return line_key

    def add_1d_plot_right(self, x, y, color=None, label="", x_label=None, ylabel=None, marker=None, linestyle=None,
                          linewidth=1):
        """ Add a line (1-d plot) at right axis
        """
        if self.axes2 is None:
            self.axes2 = self.axes.twinx()
            # print self.par1, type(self.par1)

        # Hold previous data
        self.axes2.hold(True)

        # Default
        if color is None:
            color = (0, 1, 0, 1)
        if marker is None:
            marker = 'o'
        if linestyle is None:
            linestyle = '-'

        # Special default
        if len(label) == 0:
            label = 'right'
            color = 'red'

        # color must be RGBA (4-tuple)
        r = self.axes2.plot(x, y, color=color, marker=marker, linestyle=linestyle,
                            label=label, linewidth=linewidth)
        # return: list of matplotlib.lines.Line2D object

        self.axes2.set_aspect('auto')

        # set x-axis and y-axis label
        if x_label is not None:
            self.axes2.set_xlabel(x_label, fontsize=20)
        if ylabel is not None:
            self.axes2.set_ylabel(ylabel, fontsize=20)

        # set/update legend
        self._setupLegend()

        # Register
        line_key = -1
        if len(r) == 1:
            line_key = self._lineIndex
            self._lineDict[line_key] = r[0]
            self._lineIndex += 1
        else:
            print "Impoooooooooooooooosible!"

        # Flush/commit
        self.draw()

        return line_key


    def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None):
        """ Add a 2D plot

        Arguments:
         - yticklabels :: list of string for y ticks
        """
        # Release the current image
        self.axes.hold(holdprev)

        # Do plot
        # y ticks will be shown on line 1, 4, 23, 24 and 30
        # yticks = [1, 4, 23, 24, 30]
        # self.axes.set_yticks(yticks)

        # show image
        imgplot = self.axes.imshow(array2d, extent=[xmin,xmax,ymin,ymax], interpolation='none')
        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            print "--------> [FixMe]: Set up the Y-axis ticks is erroreous"
            #self.axes.set_yticklabels(yticklabels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        # Flush...
        self._flush()

        return

    def addImage(self, imagefilename):
        """ Add an image by file
        """
        #import matplotlib.image as mpimg

        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        self._flush()

        return

    def clear_all_1d_plots(self):
        """ Remove all lines from the canvas
        """
        for ikey in self._lineDict.keys():
            plot = self._lineDict[ikey]
            if plot is None:
                continue
            if isinstance(plot, tuple) is False:
                try:
                    self.axes.lines.remove(plot)
                except ValueError as e:
                    print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
                        str(plot), len(self.axes.lines), str(e))
                self._lineDict[ikey] = None
            else:
                # error bar
                plot[0].remove()
                for line in plot[1]:
                    line.remove()
                for line in plot[2]:
                    line.remove()
                self._lineDict[ikey] = None
            # ENDIF(plot)
        # ENDFOR

        self._setupLegend()

        self.draw()

        return

    def clear_canvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        self.axes.hold(False)

        # Clear all lines
        self.clear_all_1d_plots()

        # clear image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self._colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)

        # flush/commit
        self._flush()

        return


    def getLastPlotIndexKey(self):
        """ Get the index/key of the last added line
        """
        return self._lineIndex-1


    def getPlot(self):
        """ reture figure's axes to expose the matplotlib figure to PyQt client
        """
        return self.axes

    def getXLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_xlim()

    def getYLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_ylim()

    def setXYLimit(self, xmin, xmax, ymin, ymax):
        """
        """
        # for X
        xlims = self.axes.get_xlim()
        xlims = list(xlims)
        if xmin is not None:
            xlims[0] = xmin
        if xmax is not None:
            xlims[1] = xmax
        self.axes.set_xlim(xlims)

        # for Y
        ylims = self.axes.get_ylim()
        ylims = list(ylims)
        if ymin is not None:
            ylims[0] = ymin
        if ymax is not None:
            ylims[1] = ymax
        self.axes.set_ylim(ylims)

        # try draw
        self.draw()

        return

    def remove_plot_1d(self, plot_key):
        """ Remove the line with its index as key
        :param plot_key:
        :return:
        """
        # self._lineDict[ikey].remove()
        print 'Remove line... ',

        # Get all lines in list
        lines = self.axes.lines
        assert isinstance(lines, list)

        print 'Number of lines = %d, List: %s' % (len(lines), str(lines))
        print 'Line to remove: key = %s, Line Dict has key = %s' % (str(plot_key), str(self._lineDict.has_key(plot_key)))

        if plot_key in self._lineDict:
            self.axes.lines.remove(self._lineDict[plot_key])
            self._lineDict[plot_key] = None
        else:
            raise RuntimeError('Line with ID %s is not recorded.' % plot_key)

        # Draw
        self.draw()

        return

    def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None):
        """
        """
        line = self._lineDict[ikey]

        if vecx is not None and vecy is not None:
            line.set_xdata(vecx)
            line.set_ydata(vecy)

        if linecolor is not None:
            line.set_color(linecolor)

        if linestyle is not None:
            line.set_linestyle(linestyle)

        if marker is not None:
            line.set_marker(marker)

        if markercolor is not None:
            line.set_markerfacecolor(markercolor)

        oldlabel = line.get_label()
        line.set_label(oldlabel)

        self.axes.legend()

        # commit
        self.draw()

        return

    def getLineStyleList(self):
        """
        """
        return MplLineStyles


    def getLineMarkerList(self):
        """
        """
        return MplLineMarkers

    def getLineBasicColorList(self):
        """
        """
        return MplBasicColors

    def getDefaultColorMarkerComboList(self):
        """ Get a list of line/marker color and marker style combination
        as default to add more and more line to plot
        """
        combolist = []
        nummarkers = len(MplLineMarkers)
        numcolors = len(MplBasicColors)

        for i in xrange(nummarkers):
            marker = MplLineMarkers[i]
            for j in xrange(numcolors):
                color = MplBasicColors[j]
                combolist.append( (marker, color) )
            # ENDFOR (j)
        # ENDFOR(i)

        return combolist

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w+1,h)
        self.resize(w,h)

        return

    def _setupLegend(self, location='best'):
        """ Set up legend
        self.axes.legend()
        Handler is a Line2D object. Lable maps to the line object
        """
        loclist = [
            "best",
            "upper right",
            "upper left",
            "lower left",
            "lower right",
            "right",
            "center left",
            "center right",
            "lower center",
            "upper center",
            "center"]

        # Check legend location valid or not
        if location not in loclist:
            location = 'best'

        handles, labels = self.axes.get_legend_handles_labels()
        self.axes.legend(handles, labels, loc=location)
        # print handles
        # print labels
        #self.axes.legend(self._myLegendHandlers, self._myLegentLabels)

        return
Exemple #27
0
class FigureCanvas(FigureCanvasQTAgg):
    """  A customized Qt widget for matplotlib figure.
    It can be used to replace GraphicsView of QtGui
    """

    def __init__(self, parent):
        self._driver = AddieDriver()
        # from mpl_toolkits.axes_grid1 import host_subplot
        # import mpl_toolkits.axisartist as AA
        # import matplotlib.pyplot as plt

        # Instantiating matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')

        self.axes = self.fig.add_subplot(111, projection='mantid')
        self.fig.subplots_adjust(bottom=0.15)

        # Initialize parent class and set parent
        FigureCanvasQTAgg.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvasQTAgg.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
        FigureCanvasQTAgg.updateGeometry(self)

        # Variables to manage all lines/subplot
        self._lineDict = {}
        self._lineIndex = 0

        # legend and color bar
        self._colorBar = None
        self._isLegendOn = False
        self._legendFontSize = 10

    @property
    def is_legend_on(self):
        """
        check whether the legend is shown or hide
        """
        return self._isLegendOn

    def add_arrow(self, start_x, start_y, stop_x, stop_y):
        """
        0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k')
        :return:
        """
        head_width = 0.05
        head_length = 0.1
        fc = 'k'
        ec = 'k'

        self.axes.arrrow(start_x, start_y, stop_x, stop_y, head_width,
                         head_length, fc, ec)

    def add_plot_1d(self, wkspname, wkspindex, color=None, label="", x_label=None, y_label=None,
                    marker=None, line_style=None, line_width=1, alpha=1., show_legend=True, plotError=False):

        # process inputs and defaults
        if color is None:
            color = (0, 1, 0, 1)
        if marker is None:
            marker = 'None'
        if line_style is None:
            line_style = '-'

        # color must be RGBA (4-tuple)
        wksp = self._driver.get_ws(wkspname)
        if plotError:
            r = self.axes.errorbar(wksp, wkspIndex=wkspindex, color=color, marker=marker, linestyle=line_style,
                                   label=label, linewidth=line_width, alpha=alpha,
                                   markersize=40)
        else:
            # return: list of matplotlib.lines.Line2D object
            r = self.axes.plot(wksp, wkspIndex=wkspindex, color=color, marker=marker, markersize=2, linestyle=line_style,
                               label=label, linewidth=line_width, alpha=alpha,distribution=True)

        self.axes.set_aspect('auto')

        # set x-axis and y-axis label
        if x_label is not None:
            self.axes.set_xlabel(x_label, fontsize=20)
        if y_label is not None:
            self.axes.set_ylabel(y_label, fontsize=20)

        # set/update legend
        if show_legend:
            self._setup_legend()

        # Register
        line_key = self._lineIndex
        if len(r) == 1:
            self._lineDict[line_key] = r[0]
            self._lineIndex += 1
        else:
            msg = 'Return from plot is a %d-tuple: %s.. \n' % (len(r), r)
            for i_r in range(len(r)):
                msg += 'r[%d] = %s\n' % (i_r, str(r[i_r]))
            raise NotImplementedError(msg)

        # Flush/commit
        self.draw()

        return line_key

    def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None):
        """ Add a 2D plot

        Arguments:
         - yticklabels :: list of string for y ticks
        """
        # Release the current image
        self.axes.hold(holdprev)

        # Do plot
        # y ticks will be shown on line 1, 4, 23, 24 and 30
        # yticks = [1, 4, 23, 24, 30]
        # self.axes.set_yticks(yticks)

        # show image
        imgplot = self.axes.imshow(array2d, extent=[xmin, xmax, ymin, ymax], interpolation='none')
        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            print("--------> [FixMe]: The way to set up the Y-axis ticks is wrong!")
            # self.axes.set_yticklabels(yticklabels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        # Flush...
        self._flush()

    def add_contour_plot(self, vec_x, vec_y, matrix_z):
        # create mesh grid
        grid_x, grid_y = np.meshgrid(vec_x, vec_y)

        # check size
        assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \
                                               '' % (len(vec_x), len(vec_y), matrix_z.shape)

        # Release the current image
        self.axes.hold(False)

        # Do plot
        contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100)

        labels = [item.get_text() for item in self.axes.get_yticklabels()]
        print('[DB...BAT] Number of Y labels = ', len(labels), ', Number of Y = ', len(vec_y))

        # TODO/ISSUE/55: how to make this part more powerful
        if len(labels) == 2*len(vec_y) - 1:
            new_labels = [''] * len(labels)
            for i in range(len(vec_y)):
                new_labels[i*2] = '%d' % int(vec_y[i])
            self.axes.set_yticklabels(new_labels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            contour_plot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(contour_plot)
        else:
            self._colorBar.update_bruteforce(contour_plot)

        # Flush...
        self._flush()

    def addImage(self, imagefilename):
        """ Add an image by file
        """
        #import matplotlib.image as mpimg

        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        self._flush()

    def clear_all_1d_plots(self):
        """ Remove all lines from the canvas
        """
        for ikey in list(self._lineDict.keys()):
            plot = self._lineDict[ikey]
            if plot is None:
                continue
            if isinstance(plot, tuple) is False:
                try:
                    self.axes.lines.remove(plot)
                except ValueError as e:
                    print("[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
                        str(plot), len(self.axes.lines), str(e)))
                del self._lineDict[ikey]
            else:
                # error bar
                plot[0].remove()
                for line in plot[1]:
                    line.remove()
                for line in plot[2]:
                    line.remove()
                del self._lineDict[ikey]
            # ENDIF(plot)
        # ENDFOR

        self._setup_legend()

        self.draw()

    def clear_canvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        self.axes.hold(False)

        # Clear all lines
        self.clear_all_1d_plots()

        # clear image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self._colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)
            self.fig.subplots_adjust(bottom=0.15)

        # flush/commit
        self._flush()

    def decrease_legend_font_size(self):
        """
        reset the legend with the new font size
        Returns:

        """
        # minimum legend font size is 2! return if it already uses the smallest font size.
        if self._legendFontSize <= 2:
            return

        self._legendFontSize -= 1
        self._setup_legend()

        self.draw()

    def getLastPlotIndexKey(self):
        """ Get the index/key of the last added line
        """
        return self._lineIndex-1

    def getPlot(self):
        """ reture figure's axes to expose the matplotlib figure to PyQt client
        """
        return self.axes

    def getXLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_xlim()

    def getYLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_ylim()

    def hide_legend(self):
        """
        hide the legend if it is not None
        """
        if self.axes.legend() is not None:
            # set visible to be False and re-draw
            self.axes.legend().set_visible(False)
            self.draw()

        self._isLegendOn = False

    def increase_legend_font_size(self):
        """
        reset the legend with the new font size
        """
        self._legendFontSize += 1

        self._setup_legend()

        self.draw()

    def setXYLimit(self, xmin, xmax, ymin, ymax):
        # for X
        xlims = self.axes.get_xlim()
        xlims = list(xlims)
        if xmin is not None:
            xlims[0] = xmin
        if xmax is not None:
            xlims[1] = xmax
        self.axes.set_xlim(xlims)

        # for Y
        ylims = self.axes.get_ylim()
        ylims = list(ylims)
        if ymin is not None:
            ylims[0] = ymin
        if ymax is not None:
            ylims[1] = ymax
        self.axes.set_ylim(ylims)

        # try draw
        self.draw()

    def set_title(self, title, color):
        # TODO/NOW - doc & etc

        self.axes.set_title(title, loc='center', color=color)

        self.draw()

    def remove_plot_1d(self, plot_key):
        """ Remove the line with its index as key
        """
        # Get all lines in list
        lines = self.axes.lines
        assert isinstance(lines, list), 'Lines must be list'

        if plot_key in self._lineDict:
            try:
                self.axes.lines.remove(self._lineDict[plot_key])
            except ValueError as r_error:
                error_message = 'Unable to remove to 1D line %s (ID=%d) due to %s.' % (str(self._lineDict[plot_key]),
                                                                                       plot_key, str(r_error))
                raise RuntimeError(error_message)
            # remove the plot key from dictionary
            del self._lineDict[plot_key]
        else:
            raise RuntimeError('Line with ID %s is not recorded.' % plot_key)

        self._setup_legend()

        # Draw
        self.draw()

    def show_legend(self):
        """
        show the legend if the legend is not None
        Returns:

        """
        if self.axes.legend() is not None:
            # set visible to be True and re-draw
            # self.axes.legend().set_visible(True)
            self._setup_legend()
            self.draw()

            # set flag on
            self._isLegendOn = True

    def updateLine(self, ikey, wkspname=None, wkspindex=None, vecx=None, vecy=None,
                   linestyle=None, linecolor=None, marker=None, markercolor=None):
        """
        Update a plot line or a series plot line
        """
        line = self._lineDict[ikey]
        if line is None:
            print('[ERROR] Line (key = %d) is None. Unable to update' % ikey)
            return

        if wkspname or (vecx and vecy):
            if wkspname:
                vecx, vecy, _ = self._driver.get_ws_data(wkspname, wkspindex)
            line.set_data(vecx, vecy)

        if linecolor is not None:
            line.set_color(linecolor)

        if linestyle is not None:
            line.set_linestyle(linestyle)

        if marker is not None:
            line.set_marker(marker)

        if markercolor is not None:
            line.set_markerfacecolor(markercolor)

        oldlabel = line.get_label()
        line.set_label(oldlabel)

        self._setup_legend()

        # commit
        self.draw()

    def get_data(self, line_id):
        """
        Get vecX and vecY from line object in matplotlib
        :param line_id:
        :return: 2-tuple as vector X and vector Y
        """
        # check
        if line_id not in self._lineDict:
            raise KeyError('Line ID %s does not exist.' % str(line_id))

        # get line
        line = self._lineDict[line_id]
        if line is None:
            raise RuntimeError('Line ID %s has been removed.' % line_id)

        return line.get_xdata(), line.get_ydata()

    def getLineStyleList(self):
        return LINE_STYLES

    def getLineMarkerList(self):
        return LINE_MARKERS

    def getLineBasicColorList(self):
        return BASIC_COLORS

    def getDefaultColorMarkerComboList(self):
        """ Get a list of line/marker color and marker style combination
        as default to add more and more line to plot
        """
        combo_list = list()
        num_markers = len(LINE_MARKERS)
        num_colors = len(BASIC_COLORS)

        for i in range(num_markers):
            marker = LINE_MARKERS[i]
            for j in range(num_colors):
                color = BASIC_COLORS[j]
                combo_list.append((marker, color))
            # ENDFOR (j)
        # ENDFOR(i)

        return combo_list

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w+1, h)
        self.resize(w, h)

    def _setup_legend(self, location='best'):
        """
        Set up legend
        self.axes.legend(): Handler is a Line2D object. Lable maps to the line object
        """
        allowed_location_list = [
            "best",
            "upper right",
            "upper left",
            "lower left",
            "lower right",
            "right",
            "center left",
            "center right",
            "lower center",
            "upper center",
            "center"]

        # Check legend location valid or not
        if location not in allowed_location_list:
            location = 'best'

        handles, labels = self.axes.get_legend_handles_labels()
        self.axes.legend(handles, labels, loc=location, fontsize=self._legendFontSize)

        self._isLegendOn = True
class Visualiser(Frame):
    def __init__(self, master, **kwargs):
        self.data = None
        self.pca_data = None
        self.clusters = None
        self.measurer = None
        
        self.color_conv = matplotlib.colors.ColorConverter()
        
        self.frame = Frame(master, **kwargs)
        self.frame.rowconfigure(0, weight=1)
        self.frame.columnconfigure(0, weight=1)
        
        self.figure_frame = Frame(self.frame)
        self.figure_frame.rowconfigure(0, weight=1)
        self.figure_frame.rowconfigure(1, weight=1)
        self.figure_frame.rowconfigure(2, weight=1)
        self.figure_frame.columnconfigure(0, weight=1)
        self.figure_frame.columnconfigure(1, weight=1)
        self.figure = Figure(figsize=(5,5), dpi=100)
        self.canvas = FigureCanvasTkAgg(self.figure, self.figure_frame)
        self.figure_subplot = self.figure.add_subplot("111")
        self.canvas.show()
        self.canvas.get_tk_widget().pack(fill=BOTH, expand=1)
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.figure_frame)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(fill=BOTH, expand=1)
        self.figure_frame.grid(row=0, sticky=N+E+S+W)
        
        self.controls_frame = Frame(self.frame)
        
        self.show_points = IntVar()
        self.show_points.set(1)
        self.show_points_c = Checkbutton(self.controls_frame, text="Show Points", 
                                         variable=self.show_points)
        self.show_points_c.grid(row=0, column=0, sticky=N+E+S+W)
        
        self.show_convex_hull = IntVar()
        self.show_convex_hull_c = Checkbutton(self.controls_frame, text="Show Convex Hull", 
                                         variable=self.show_convex_hull)
        self.show_convex_hull_c.grid(row=0, column=1, sticky=N+E+S+W)
        
        self.show_centers = IntVar()
        self.show_centers_c = Checkbutton(self.controls_frame, text="Show Cluster Centers", 
                                         variable=self.show_centers)
        self.show_centers_c.grid(row=0, column=2, sticky=N+E+S+W)
        
        self.show_ellipse = IntVar()
        self.show_ellipse_c = Checkbutton(self.controls_frame, text="Show Variance Ellipse", 
                                         variable=self.show_ellipse)
        self.show_ellipse_c.grid(row=1, column=0, sticky=N+E+S+W)
        
        self.show_3D = IntVar()
        self.show_3D_c = Checkbutton(self.controls_frame, text="Show in 3D (If possible)", 
                                         variable=self.show_3D)
        self.show_3D_c.grid(row=1, column=1, sticky=N+E+S+W)
        
        self.rerender_b = Button(self.controls_frame, text="Rerender visualisation", command=self.render)
        self.rerender_b.grid(row=2, columnspan=2, sticky=N+E+S+W)
        self.controls_frame.grid(row=1, sticky=N+E+S+W)
        
    def grid(self, **kwargs):
        self.frame.grid(**kwargs)
        
    def pack(self, **kwargs):
        self.frame.pack(**kwargs)
    
    def load_data(self, data, clusters):
        self.measurer = clustermeasures.ClusterMeasures()
        self.measurer.load_clustered_data(data, clusters)
        self.measurer.calculate_measures()
        self.data = self.measurer._data
        self.clusters = self.measurer._clusters
        self.pca_data = mlab.PCA(np.matrix(self.data)).Y
        
        self.colors = [self.color_conv.to_rgb((random.random(), random.random(), random.random()))
                  for i in range(self.measurer._num_clusters)]
        
    def render(self):
        #Display the 2d PCA of the clustered data
        num_clusters = self.measurer._num_clusters
        clusters = [[] for i in range(num_clusters)]
        self.figure.delaxes(self.figure_subplot)
        ############ DISPLAY IN 3D ################
        if self.show_3D.get():
            self.figure_subplot = self.figure.add_subplot(111, projection='3d')
            self.figure_subplot.hold(True)
            color = 0
            for cluster in self.measurer.pca_3d_clustered:
                if self.show_ellipse.get():
                    centroid = find_centroid(cluster)
                    variance = np.var(cluster, 0)
                    stddev = [math.sqrt(v) for v in variance]
                    ## your ellispsoid and center in matrix form
                    A = np.array([[stddev[0],0,0],[0,stddev[1],0],[0,0,stddev[2]]])
                    A = np.cov(np.matrix(cluster), rowvar=0)
                    center = centroid
                    #Two standard deviations of data
                    N = 2;
                    ## find the rotation matrix and radii of the axes
                    U, s, rotation = linalg.svd(A)
                    radii = N*np.sqrt(s)

                    # now carry on with EOL's answer
                    u = np.linspace(0.0, 2.0 * np.pi, 100)
                    v = np.linspace(0.0, np.pi, 100)
                    x = radii[0] * np.outer(np.cos(u), np.sin(v))
                    y = radii[1] * np.outer(np.sin(u), np.sin(v))
                    z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
                    for i in range(len(x)):
                        for j in range(len(x)):
                            [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation) + center
                    self.figure_subplot.plot_wireframe(x, y, z,  rstride=4, cstride=4, color=self.colors[color], alpha=0.5)
                    
                if self.show_points.get():
                    self.figure_subplot.scatter([e[0] for e in cluster], [e[1] for e in cluster], [e[2] for e in cluster], c=self.colors[color], marker='o', alpha=.6)
                    
                if self.show_centers.get():
                    center = find_centroid(cluster)
                    self.figure_subplot.scatter(center[0], center[1], center[2], color=self.colors[color], marker='*',s=100)
                color += 1
                
        ################## DISPLAY IN 2D ###################
        if not self.show_3D.get():
            self.figure_subplot = self.figure.add_subplot("111")
            self.figure_subplot.hold(True)
            
            for i in range(num_clusters):
                cluster = self.measurer.pca_2d_clustered[i]
                color = self.colors[i]
                if self.show_points.get():
                    self.figure_subplot.scatter([e[0] for e in cluster], [e[1] for e in cluster], color=color, marker='o')
                if self.show_centers.get():
                    center = find_centroid(self.measurer.pca_2d_clustered[i])
                    self.figure_subplot.scatter(center[0], center[1], color=color, marker='*',s=100)
                #Plot the convex hull
                if self.show_convex_hull.get():
                    self.display_convex_hull(cluster, self.colors[i])
                
                
        self.figure_subplot.hold(False)
        self.canvas.show()
        
    def display_convex_hull(self, cluster, color):
        cluster = np.matrix(cluster)
        try:
            hull = ConvexHull(cluster)
        except:
            return False
        for simplex in hull.simplices:
            self.figure_subplot.plot(cluster[simplex, 0], cluster[simplex, 1], color=color)
Exemple #29
0
class Qt4Mpl2dCanvas(FigureCanvas):
    """  A customized Qt widget for matplotlib 2D image.
    It can be used to replace GraphicsView
    """
    def __init__(self, parent):
        """  Initialization
        """
        # Instantiating matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')

        self.axes = self.fig.add_subplot(
            111)  # return: matplotlib.axes.AxesSubplot

        # Initialize parent class and set parent
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        # legend and color bar
        self._colorBar = None

        # Buffer of data
        self._currentArray2D = None

        # image management data structure
        self._currIndex = 0
        self._imagePlotDict = dict()

        # image size
        self._xLimit = [0., 1.]
        self._yLimit = [0., 1.]

        return

    @property
    def array2d(self):
        """
        get the matrix plot now
        :return:
        """
        return self._currentArray2D

    def add_2d_plot(self,
                    array2d,
                    x_min,
                    x_max,
                    y_min,
                    y_max,
                    hold_prev,
                    yticklabels=None):
        """ Add a 2D plot
        Requirements:
        (1) a valid 2-dimensional numpy.ndarray
        (2) x_min, x_max, y_min, y_max are of right order
        Guarantees: a 2D fill-plot is made
        :param array2d:
        :param x_min:
        :param x_max:
        :param y_min:
        :param y_max:
        :param hold_prev: hold previous image.  If False, all 2D image and polygon patches will be removed
        :param yticklabels: list of string for y ticks
        :return:
        """
        # Check
        assert isinstance(
            array2d, np.ndarray
        ), 'Input array2d must be a numpy array but not %s.' % str(
            type(array2d))
        assert isinstance(x_min, int) and isinstance(x_max, int) and x_min < x_max, \
            'x_min = %s (of type %s) should be less than x_max = %s (of type %s).' \
            '' % (str(x_min), str(type(x_min)), str(x_max), str(type(x_max)))
        assert isinstance(y_min, int) and isinstance(y_max,
                                                     int) and y_min < y_max

        # Release the current image
        self.axes.hold(hold_prev)

        # show image
        img_plot = self.axes.imshow(array2d,
                                    extent=[x_min, x_max, y_min, y_max],
                                    interpolation='none')
        self._currentArray2D = array2d

        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            # FUTURE-VZ : The way to set up the Y-axis ticks is wrong!"
            # self.axes.set_yticklabels(yticklabels)
            print(
                '[Warning] The method to set up the Y-axis ticks to 2D image is wrong!'
            )

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            img_plot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(img_plot)
        else:
            self._colorBar.update_bruteforce(img_plot)

        # Flush...
        self._flush()

        # Add the image management
        self._currIndex += 1
        self._imagePlotDict[self._currIndex] = img_plot

        return self._currIndex

    def add_patch(self, patch):
        """
        add an artist patch such as polygon
        :param patch:
        :return:
        """
        self.axes.add_artist(patch)

        # Flush...
        self._flush()

        return

    def addImage(self, imagefilename):
        """ Add an image by file
        """
        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img,
                                   extent=[0, 1000, 800, 0],
                                   interpolation='none',
                                   origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        self._flush()

        return

    def clear_canvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        self.axes.hold(False)

        # clear 2D image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self._colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)
        # END-FOR

        # flush/commit
        self._flush()

        return

    def plot_polygon(self, vertex_array, fill=False, color='w'):
        """
        Plot a new polygon
        :param vertex_array:
        :param fill:
        :param color:
        :return:
        """
        # check requirements
        assert isinstance(vertex_array, np.ndarray)
        assert isinstance(fill, bool)
        assert isinstance(color, str)

        # plot polygon
        p = plt.Polygon(vertex_array, fill=fill, color=color)
        self.axes.add_artist(p)

        # Flush...
        self._flush()

        return p

    @property
    def x_min(self):
        """ x minimum
        :return:
        """
        return self._xLimit[0]

    @property
    def x_max(self):
        """ maximum x
        :return:
        """
        return self._xLimit[1]

    @property
    def y_min(self):
        """ minimum y
        :return:
        """
        return self._yLimit[0]

    @property
    def y_max(self):
        """ maximum y
        :return:
        """
        return self._yLimit[1]

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w + 1, h)
        self.resize(w, h)

        return
Exemple #30
0
class GraphPanel(wx.Panel):
    def __init__(self,parent,ctrl):
        wx.Panel.__init__(self,parent)
        self.SetBackgroundColour('#FFFFFF')
        self.SetSizeWH(500,600)
        self.ctrlPanel = ctrl
        self.initGraph()
        wx.EVT_PAINT(self, self.OnPaint)


    def initGraph(self):
        self.trial = 1
        self.sbs = {}
        self.sbs['Lever'] = ScatterBrain('Lever','#3399FF','s')
        self.sbs['Mark'] = ScatterBrain('Mark','#000000','x')
        for i in range(0,8):
            name = 'aTaste%d'%i
            self.sbs[name] = ScatterBrain(name,Ferret.TasteColors[i],'o')
            name2 = 'mTaste%d'%i
            self.sbs[name2] = ScatterBrain(name2,Ferret.TasteColors[i],'o',False)
        
        self.figure = Figure(dpi=100,figsize=(5,5.8))
        self.axes = self.figure.add_subplot(111)
        self.axes.axis([0,X.trialDuration,0,1.5])
        self.axes.set_xlabel('time (s)')


        for i in X.intervalList:
            if isinstance(i, Intervals.WaitInt):
                continue
            color = Ferret.iColors[i.type]
            if isinstance(i, Intervals.ToneInt):
                color = Ferret.freq2color(i.freq)
            self.axes.axvspan(i.startTime,i.startTime+i.duration,facecolor=color,alpha=0.5,lw=0.0, zorder=0)
            
        
        LText = FontProperties()
        LText.set_size("small")
        
        
        self.axes.legend((self.sbs['Lever'].getPlot(self.axes),self.sbs['Mark'].getPlot(self.axes),
                          self.sbs['aTaste1'].getPlot(self.axes),self.sbs['mTaste1'].getPlot(self.axes)),
                         ("Lever Press","Time Marked", "Reward Given","Manual Reward"),
                         prop=LText, fancybox=True, bbox_to_anchor=(0., 1.02, 1., .102), loc=1, ncol=2, mode="expand", borderaxespad=0)
        
        self.canvas = FigureCanvas(self, -1, self.figure)
    
    def clearGraph(self):
        self.figure.delaxes(self.axes)
        self.initGraph()
        self.Refresh()
    
    def addPoint(self,t,pcat):
        if pcat<8:
            self.sbs['aTaste%d'%pcat].addPoint(t,self.trial)
        elif pcat<16:
            self.sbs['mTaste%d'%(pcat-8)].addPoint(t,self.trial)
        elif pcat==30:
            self.sbs['Lever'].addPoint(t,self.trial)
        elif pcat==31:
            self.sbs['Mark'].addPoint(t,self.trial)
    
    def newTrial(self):
        self.trial+=1
        self.axes.set_ylim(top=(self.trial+0.5))
        
    def OnPaint(self, event):
        for k,v in self.sbs.items():
            v.getPlot(self.axes)
        self.canvas.draw()
        event.Skip()

    def OnSetFocus(self, event):
        self.color = 'yellow'
        self.Refresh()

    def OnKillFocus(self, event):
        self.color = '#b3b3b3'
        self.Refresh()
    
    def saveGraph(self,filename="graph.png"):
        self.figure.savefig(filename)
Exemple #31
0
class MyGui:

    def __init__(self):
        self.window = Tk()
        self.window.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.xvals = []
        self.yvals = []

        """
        but = Button(self.window, text = "Start", font = "Calibri 20", width = 6, height = 1)
        but.grid(row = 3, column = 3)
        """
        # Frame1
        self.frame1 = Frame(self.window)
        self.frame1.grid(row=0, column=0)

        lab = Label(self.frame1, text="File Header:", font="calibri 20", width=10, height=1, anchor="e")
        lab.grid(row=0, column=0, sticky="E", pady=15)

        self.headerentry = ScrolledText(self.frame1, height=3, width=20)
        self.headerentry.grid(row=0, column=1, sticky="E")

        lab = Label(self.frame1, text="File Path:", font="calibri 20", width=10, height=1, anchor="e")
        lab.grid(row=1, column=0)
        buttonpath = Button(self.frame1, text="Browse", command=self.browse_button, font="calibri 20", width=11,
                            height=1, anchor="center")
        buttonpath.grid(row=1, column=1, sticky="w", pady=(0, 5))
        # Frame1 End

        # Frame3
        widthtime = 3
        self.frame3 = Frame(self.window)
        self.frame3.grid(row=1, column=0)
        lab = Label(self.frame3, text="Duration:", font="calibri 20", width=8, height=1)
        lab.grid(row=1, column=0, sticky="e", padx=(0, 20))
        self.dayE = Entry(self.frame3, width=widthtime)
        self.dayE.grid(row=0, column=2, padx=(5, 18))
        lab = Label(self.frame3, text="Days:", font="calibri 15")
        lab.grid(row=0, column=1, sticky="e")
        self.hourE = Entry(self.frame3, width=widthtime)
        self.hourE.grid(row=1, column=2, padx=(5, 18))
        lab = Label(self.frame3, text="Hours:", font="calibri 15")
        lab.grid(row=1, column=1, sticky="e")
        self.minutesE = Entry(self.frame3, width=widthtime)
        self.minutesE.grid(row=2, column=2, padx=(5, 18))
        lab = Label(self.frame3, text="Minutes:", font="calibri 15")
        lab.grid(row=2, column=1, sticky="e")
        lab = Label(self.frame3, text="Interval:", font="calibri 20")
        lab.grid(row=3, column=0, padx=(0, 20))
        lab = Label(self.frame3, text="Seconds:", font="calibri 15")
        lab.grid(row=3, column=1, sticky="e")
        self.entryT = Entry(self.frame3, width=widthtime)
        self.entryT.grid(row=3, column=2, padx=(5, 18))

        # Frame3 End

        # Frame5 Start
        self.frame5 = Frame(self.window)
        self.frame5.grid(row=3, column=0)
        lab = Label(self.frame5, text="DMM:", font="calibri 20")
        lab.grid(row=0, column=0, sticky="e", padx=10)
        but = Button(self.frame5, text="Ping", command=self.ping, font="calibri 12", pady=2)
        but.grid(row=0, column=3, padx=10)
        but = Button(self.frame5, text="R", command=self.ping, font="calibri 12", pady=2)
        but.grid(row=0, column=4, padx=10)
        self.dropdowncom(self.frame5)

        # self.batterystat = Progressbar(self.frame5, orient=HORIZONTAL, length=100, mode="determinate")
        # self.batterystat.grid(row=1, column=0, columnspan=2)
        # Frame5 End

        # Frame7

        self.frame7 = Frame(self.window)
        self.frame7.grid(column=1, row=3)
        self.batlabel = Label(self.frame7, text="Battery: n/a %", font="calibri 15")
        self.batlabel.grid(row=0, column=1, padx=20)
        but = Button(self.frame7, text="Start", command=self.startmeas, font="calibri 15")
        but.grid(row=0, column=2, padx=(10, 0))
        self.percentlab = Label(self.frame7, text="Progress: 0%", font="calibri 15")
        self.percentlab.grid(row=0, column=0, padx=(0, 10))

        # Frame Graph

        self.frame8 = Frame(self.window)
        self.frame8.grid(row=0, column=1, rowspan=2)

        self.fig = Figure(figsize=(5, 4), dpi=100)
        self.suba = self.fig.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame8)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

        # Frame Graph End

    def dropdowncom(self, frame):

        find_com = serial.tools.list_ports
        COM = find_com.comports()
        self.COM_LIST = []
        for x in COM:
            self.COM_LIST.append(x[0])

        if self.COM_LIST == []:
            self.COM_LIST.append("COM0")

        self.dmmcom = StringVar(self.window)
        self.dmmcom.set(self.COM_LIST[0])
        self.DMM = OptionMenu(frame, self.dmmcom, *self.COM_LIST)
        self.DMM.grid(column=1, row=0, sticky="e")
        self.DMM.config(width=5, height=1, highlightthickness=0, font="Calibri 14")

    def updatecoms(self):
        print("update")
        find_com = serial.tools.list_ports
        COM = find_com.comports()
        self.COM_LIST = []
        for x in COM:
            self.COM_LIST.append(x[0])

        if self.COM_LIST == []:
            self.COM_LIST.append("COM0")

        self.dmmcom.set('')
        self.DMM['menu'].delete(0, 'end')

        new_choices = self.COM_LIST

        for choice in new_choices:
            self.DMM['menu'].add_command(label=choice, command=tkinter._setit(self.dmmcom, choice))

        self.dmmcom.set(self.COM_LIST[0])

    def updatecoms(self):
        print("update")
        find_com = serial.tools.list_ports
        COM = find_com.comports()
        self.COM_LIST = []
        for x in COM:
            self.COM_LIST.append(x[0])

        if self.COM_LIST == []:
            self.COM_LIST.append("COM0")

        self.dmmcom.set('')
        self.DMM['menu'].delete(0, 'end')

        new_choices = self.COM_LIST

        for choice in new_choices:
            self.DMM['menu'].add_command(label=choice, command=tkinter._setit(self.dmmcom, choice))

        self.dmmcom.set(self.COM_LIST[0])

    def start(self):
        self.window.mainloop()

    def browse_button(self):
        print("Browse")
        self.filename = filedialog.askdirectory()
        print(self.filename)

    def ping(self):

        self.dmm = Connection()
        self.dmm.initialize(self.dmmcom.get())
        self.dmm.finddevice()
        self.batlabel["text"] = "Battery: " + str(self.dmm.getbattery()) + "%"
        self.dmm.kill()

    def gettime(self):

        try:
            d = int(self.dayE.get())
        except:
            d = 0
        try:
            h = int(self.hourE.get())
        except:
            h = 0
        try:
            m = float(self.minutesE.get())
        except:
            m = 0
        try:
            timeb = float(self.entryT.get())
        except:
            timeb = 3

        self.time = d * 24 * 60 * 60 + h * 60 * 60 + m * 60
        self.timebet = timeb

    def startmeas(self):
        self.suba.clear()

        print("clear")
        self.gettime()
        numberofmeas = self.time / self.timebet
        numberofmeas = int(numberofmeas)
        print(numberofmeas)
        time = 0
        path = self.filename + "/measurement.txt"
        file = open(path, "w")
        file.write(self.headerentry.get('1.0', END) + "\n")
        file.write("Meassurement[n]; Time[s]; Value; Unit \n")
        file.close()
        com = self.dmmcom.get()
        self.dmm.initialize(com)
        unitdmm = self.dmm.getsetup()[0]
        self.xvals = []
        self.yvals = []

        for x in range(numberofmeas):
            self.dmm.initialize(com)
            value = self.dmm.getValue()
            self.dmm.kill()
            file = open(path, "a")
            print(x, time)
            linewr = ("%d;%.3f;%.6f;%s \n" % (x, time, value, unitdmm))
            self.xvals.append(time)
            self.yvals.append(value)
            print(linewr)
            file.write(linewr)
            file.close()
            self.fig.delaxes(self.suba)
            self.suba = self.fig.add_subplot(111)
            #xvals = self.xvals[-20:]
            #yvals = self.yvals[-20:]
            xvals = self.xvals
            yvals = self.yvals
            self.suba.plot(xvals, yvals, color="blue")
            self.canvas.draw()
            percent = (x / numberofmeas) * 100
            self.percentlab["text"] = ("Progress: %.2f" % percent)  # Showing percentage in Gui
            self.sleep(self.timebet)
            time = time + self.timebet

        file.close()

    def rgraph(self):

        self.fig = Figure(figsize=(5, 4), dpi=100)
        self.suba = self.fig.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame8)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

    def sleep(self, x):

        duration = 0
        start = time.perf_counter()
        print("sleep")
        while duration <= x:
            time.sleep(0.005)
            self.window.update()
            duration = time.perf_counter() - start

    def on_closing(self):
        if messagebox.askokcancel("Quit",

                                  "Do you want to quit?\n some meassurement will be lost\n and the programm will stop meassuring"):
            self.window.destroy()
Exemple #32
0
class App:
    def __init__(self, master):

        # create toplevel window
        frame = Frame(master)

        frame.grid(ipadx=10, ipady=10)

        self.wdir = os.getcwd() + '/'
        self.I = pp.Image()
        self.Tool = pp.Tools()

        self.lb1 = Label(frame, text="Nstep").grid(row=0, column=0)

        self.enstep = Entry(frame, width=8)
        self.enstep.grid(row=0, column=1)
        self.enstep.insert(0, "0")

        self.LoadedNstep = StringVar()
        self.PresentTime = StringVar()

        self.myData = self.loaddata()
        self.varkeys = self.myData.get_varinfo()['allvars']
        self.grid_dict = self.myData.grid()

        if self.grid_dict["n3"] != 1:
            self.Geom = '3D'
        elif self.grid_dict["n3"] == 1 and self.grid_dict["n2"] != 1:
            self.Geom = '2D'
        else:
            self.Geom = '1D'

        self.ldatabutton = Button(frame,
                                  text="Load data",
                                  command=self.loaddata)
        self.ldatabutton.grid(row=0, column=2)

        ############### MARK THE CUTS #################################

        self.ex1 = Entry(frame, width=5)
        self.ex1.grid(row=2, column=0)
        self.ex1.insert(0, "x1")

        self.ex2 = Entry(frame, width=5)
        self.ex2.grid(row=2, column=1)
        self.ex2.insert(0, "x2")

        self.ex3 = Entry(frame, width=5)
        self.ex3.grid(row=2, column=2)
        self.ex3.insert(0, "x3")

        if self.Geom == '2D':
            self.ex3.config(state='disabled')

        if self.Geom == '1D':
            self.ex3.config(state='disabled')
            self.ex2.config(state='disabled')
            self.ex1.config(state='disabled')

        # place a graph somewhere here
        self.f = Figure(figsize=(7, 7), dpi=100)
        self.a = self.f.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.f, master=root)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(row=0,
                                         column=3,
                                         columnspan=10,
                                         rowspan=10,
                                         sticky=E)

        #self.toolbar = NavigationToolbar2TkAgg(self.canvas,tl)
        #self.toolbar.update()
        #self.canvas._tkcanvas.grid(row=60,column=15,sticky=E)

        self.v = StringVar()
        self.v.set("None")

        ################ VARIABLES TO PLOT #################################

        for j in range(len(self.varkeys)):
            self.ldata = Radiobutton(frame,
                                     text=self.varkeys[j],
                                     variable=self.v,
                                     value=self.varkeys[j],
                                     command=self.getmyvar)
            self.ldata.grid(row=3 + j, column=0, sticky=W)

################ SLICES CHOICE #################################

        self.slvar = StringVar()
        self.slvar.set("Choose Slice")
        if self.Geom == '3D':
            SliceList = ("Along x1", "Along x2", "Along x3", "Along x1-x2",
                         "Along x2-x3", "Along x3-x1")
        elif self.Geom == '2D':
            SliceList = ("Along x1", "Along x2", "Along x1-x2")
        else:
            SliceList = ()

        for j in range(len(SliceList)):
            self.sldata = Radiobutton(frame,
                                      text=SliceList[j],
                                      variable=self.slvar,
                                      value=SliceList[j],
                                      command=self.setslice)
            self.sldata.grid(row=3 + j, column=1, sticky=W)

############### PLOT PROPERTIES #################################

        self.logvar = IntVar()
        self.chkb = Checkbutton(frame,
                                text="Log  ",
                                variable=self.logvar,
                                onvalue=1,
                                offvalue=0,
                                command=self.logchkcall)
        self.chkb.grid(row=3, column=2, sticky=W)  #(row=15,column=0,sticky=W)

        self.polarvar = IntVar()
        self.polchkb = Checkbutton(frame,
                                   text="Polar",
                                   variable=self.polarvar,
                                   onvalue=1,
                                   offvalue=0,
                                   command=self.polchkcall)
        self.polchkb.grid(row=4, column=2, sticky=W)  #(row=15,column=1)
        if self.Geom == '1D':
            self.polchkb.config(state='disabled')
            self.polarvar.set(0)

        self.preaspect = IntVar()
        self.aspectb = Checkbutton(frame,
                                   text="Aspect",
                                   variable=self.preaspect,
                                   onvalue=1,
                                   offvalue=0,
                                   command=self.aspchkcall)
        self.aspectb.grid(row=5, column=2, sticky=W)  #(row=15,column=2)
        if self.Geom == '1D':
            self.aspectb.config(state='disabled')

################ X and Y LABELS #################################

        self.lb2 = Label(frame, text="Labels").grid(row=22, column=0)

        self.xlb = Entry(frame, width=15)
        self.xlb.grid(row=22, column=1)
        self.xlb.insert(0, "xlabel")

        self.ylb = Entry(frame, width=15)
        self.ylb.grid(row=22, column=2)
        self.ylb.insert(0, "ylabel")

        ############### X and Y RANGE#######################

        self.lb2a = Label(frame, text="XRange").grid(row=24, column=0)
        self.lb2b = Label(frame, text="YRange").grid(row=26, column=0)
        self.lb2c = Label(frame, text="VarRange").grid(row=28, column=0)

        self.xrmin = Entry(frame, width=15)
        self.xrmin.grid(row=24, column=1)
        self.xrmin.insert(0, '')
        self.xrmax = Entry(frame, width=15)
        self.xrmax.grid(row=24, column=2)
        self.xrmax.insert(0, '')

        self.yrmin = Entry(frame, width=15)
        self.yrmin.grid(row=26, column=1)
        self.yrmin.insert(0, '')
        self.yrmax = Entry(frame, width=15)
        self.yrmax.grid(row=26, column=2)
        self.yrmax.insert(0, '')

        self.varmin = Entry(frame, width=15)
        self.varmin.grid(row=28, column=1)
        self.varmin.insert(0, '')
        self.varmax = Entry(frame, width=15)
        self.varmax.grid(row=28, column=2)
        self.varmax.insert(0, '')
        if self.Geom == '1D':
            self.yrmin.config(state='disabled')
            self.yrmax.config(state='disabled')

################ CONTOURS #################################

        self.lb3 = Label(frame, text="Contours").grid(row=16, column=0)

        self.contvar = IntVar()
        self.chkb = Checkbutton(frame,
                                text="Contour",
                                variable=self.contvar,
                                onvalue=1,
                                offvalue=0,
                                command=self.contchkcall)
        self.chkb.grid(row=6, column=2, sticky=W)  #(row=16,column=0,sticky=W)

        self.plcont = StringVar()
        self.contkeys = ["None"]
        if "b1" in self.varkeys:
            for item in self.varkeys:
                self.contkeys.append(item)
            self.contkeys.append("x1*b3")
            self.contkeys.append("x1*A3")
        else:
            for item in self.varkeys:
                self.contkeys.append(item)
        self.plcont.set("None")
        self.contmenu = OptionMenu(frame, self.plcont, *self.contkeys)
        self.contmenu.grid(row=16, column=1)

        self.xlevb = Entry(frame, width=15)
        self.xlevb.grid(row=16, column=2, sticky=W)
        self.xlevb.insert(0, "Levels")
        self.xlevb.config(state='disabled')
        self.contmenu.config(state='disabled')

        if self.Geom == '1D':
            self.chkb.config(state='disabled')

################ ARROWS #################################

        self.lb4 = Label(frame, text="Arrows").grid(row=19, column=0)

        self.arrowvar = IntVar()
        self.arrowchkb = Checkbutton(frame,
                                     text="Arrows",
                                     variable=self.arrowvar,
                                     onvalue=1,
                                     offvalue=0,
                                     command=self.arrchkcall)
        self.arrowchkb.grid(row=7, column=2,
                            sticky=W)  #(row=16,column=0,sticky=W)

        self.arrspb = Entry(frame, width=15)
        self.arrspb.grid(row=19, column=2, sticky=W)
        self.arrspb.insert(0, "20")

        self.plarr = StringVar()
        self.arrkeys = ["None"]
        self.arrkeys.append("Vp")
        self.arrkeys.append("Vp_norm")
        if "b1" in self.varkeys:
            self.arrkeys.append("Bp")
            self.arrkeys.append("Bp_norm")
        self.plarr.set("None")
        self.arrmenu = OptionMenu(frame, self.plarr, *self.arrkeys)
        self.arrmenu.grid(row=19, column=1)
        self.arrmenu.config(state='disabled')
        self.arrspb.config(state='disabled')

        if self.Geom == '1D':
            self.arrowchkb.config(state='disabled')

################ VARIOUS PLOTTING BUTTONS #################################

        self.pltbutton = Button(frame, text="Plot", command=self.plotfinal)
        self.pltbutton.grid(row=36, column=0)
        if self.Geom == '1D':
            self.pltbutton.config(state='active')
        else:
            self.pltbutton.config(state='disabled')

        self.surfbutton = Button(frame,
                                 text="Surface",
                                 command=self.plotsurface)
        self.surfbutton.grid(row=36, column=1)
        self.surfbutton.config(state='disabled')
        #if self.Geom == '1D':
        #    self.surfbutton.config(state='disabled')

        self.clrbutton = Button(frame, text="Clear", command=self.plotclear)
        self.clrbutton.grid(row=36, column=2)

        ################ INFORMATION #################################

        self.lbinf0 = Label(frame,
                            text="Information",
                            font=("Times", 12, "bold"))
        self.lbinf0.grid(row=47, column=0, sticky=W, columnspan=3)

        self.lbinf1a = Label(frame, text="Dir :",
                             font=("Times", 10, "bold")).grid(row=49,
                                                              column=0,
                                                              sticky=W,
                                                              columnspan=3)
        self.lbinf1 = Label(frame, text=self.wdir).grid(row=50,
                                                        column=0,
                                                        sticky=W,
                                                        columnspan=3)
        self.lbinf2a = Label(frame,
                             text="Domain :",
                             font=("Times", 10, "bold")).grid(row=51,
                                                              column=0,
                                                              sticky=W,
                                                              columnspan=3)
        self.lbinf2 = Label(
            frame,
            text="n1 x n2 x n3 =  %d x %d x %d " %
            (self.grid_dict.get('n1'), self.grid_dict.get('n2'),
             self.grid_dict.get('n3'))).grid(row=52,
                                             column=0,
                                             sticky=W,
                                             columnspan=3)
        self.lbinf3a = Label(frame,
                             text="Time Status",
                             font=("Times", 10, "bold")).grid(row=53,
                                                              column=0,
                                                              sticky=W,
                                                              columnspan=3)
        self.lbinf4 = Label(frame,
                            text="Nlast = %d" %
                            (pp.nlast_info().get('nlast'))).grid(row=54,
                                                                 column=0,
                                                                 sticky=W,
                                                                 columnspan=3)
        self.lbinf5 = Label(frame,
                            textvariable=self.LoadedNstep).grid(row=55,
                                                                column=0,
                                                                sticky=W,
                                                                columnspan=3)
        self.lbinf6 = Label(frame,
                            textvariable=self.PresentTime).grid(row=56,
                                                                column=0,
                                                                sticky=W,
                                                                columnspan=3)


################ VARIOUS FUNCTIONS #################################

    def loaddata(self):
        try:
            int(self.enstep.get().strip().split()[0])
        except (ValueError, IndexError):
            print "Specify the proper value of Nstep"
        else:
            mynstep = int(self.enstep.get())
            self.D = pp.pload(mynstep, w_dir=self.wdir)
            self.LoadedNstep.set("Loaded Nstep = " + self.enstep.get())
            self.PresentTime.set("Present Time = " +
                                 str(self.D.time_info()['time']) + " [cu]")
            return self.D

    def getmyvar(self):
        try:
            self.v.get() != "None"
        except KeyError:
            print "Specify the variable to plot"
        else:
            self.myvar = self.v.get()

    def logchkcall(self):
        self.logchk = self.logvar.get()

    def contchkcall(self):
        self.contchk = self.contvar.get()
        if self.contchk == 1:
            self.contmenu.config(state='normal')
            self.xlevb.config(state='normal')
        else:
            self.contmenu.config(state='disabled')
            self.xlevb.config(state='disabled')

    def arrchkcall(self):
        self.arrchk = self.arrowvar.get()
        if self.arrchk == 1:
            self.arrmenu.config(state='normal')
            self.arrspb.config(state='normal')
        else:
            self.arrmenu.config(state='disabled')
            self.arrspb.config(state='disabled')

    def aspchkcall(self):
        self.aspchk = self.preaspect.get()

    def polchkcall(self):
        self.polchk = self.polarvar.get()

    def setslice(self):
        self.slicename = self.slvar.get()
        if self.slicename == "Along x1" or self.slicename == "Along x2" or self.slicename == "Along x3":
            self.surfbutton.config(state='disabled')
            self.arrowchkb.config(state='disabled')
            self.arrowvar.set(0)
            self.chkb.config(state='disabled')
            self.contvar.set(0)
            self.pltbutton.config(state='active')
            self.polchkb.config(state='disabled')
            self.polarvar.set(0)
        else:
            self.pltbutton.config(state='disabled')
            self.arrowchkb.config(state='normal')
            self.chkb.config(state='normal')
            self.surfbutton.config(state='active')
            self.polchkb.config(state='normal')

        if self.slicename == "Along x2-x3":
            self.polchkb.config(state='disabled')
            self.polarvar.set(0)

    def plotclear(self):
        self.a.clear()

        if len(self.f.axes) > 1:
            self.f.delaxes(self.f.axes[1])
            self.f.subplots_adjust(right=0.90)

        self.canvas.show()

    def plotfinal(self):
        if self.getplotvar() == True:
            self.a.axis([
                self.getxaxisrange()[0],
                self.getxaxisrange()[1],
                self.getvarrange()[0],
                self.getvarrange()[1]
            ])
            self.a.plot(self.x, self.var)
            self.a.set_aspect('auto')
        self.a.set_xlabel(self.xlb.get())
        self.a.set_ylabel(self.ylb.get())
        self.canvas.show()

    def plotsurface(self):
        tdum = time.time()
        self.plotclear()

        if self.preaspect.get() == 1:
            self.a.set_aspect('equal')
        else:
            self.a.set_aspect('auto')

        if self.polarvar.get() == 1:
            if self.drawpolar() == True:
                self.a.axis([
                    self.getxaxisrange()[0],
                    self.getxaxisrange()[1],
                    self.getyaxisrange()[0],
                    self.getyaxisrange()[1]
                ])
                self.image = self.a.imshow(self.SphData[self.myvar],
                                           origin='lower',
                                           extent=self.extent,
                                           interpolation='nearest',
                                           cmap="jet",
                                           vmin=self.getvarrange()[0],
                                           vmax=self.getvarrange()[1])
                self.f.colorbar(self.image)
        else:
            if self.getsurfvar() == True:
                self.a.axis([
                    self.getxaxisrange()[0],
                    self.getxaxisrange()[1],
                    self.getyaxisrange()[0],
                    self.getyaxisrange()[1]
                ])
                self.image = self.a.pcolormesh(self.x,
                                               self.y,
                                               self.var,
                                               cmap='jet',
                                               vmin=self.getvarrange()[0],
                                               vmax=self.getvarrange()[1])
                self.f.colorbar(self.image)

        if self.contvar.get() == 1:
            try:
                self.plcont.get() != "None"
            except KeyError:
                print "Specify the variable for Contour"
            else:
                self.drawcontour()
                self.contlevlist = []
                self.contlevstr = string.split(self.xlevb.get(), ',')
                try:
                    if self.contlevstr[0] == 'log':
                        self.flevel = self.contlevstr[1]
                        self.varcont = log10(self.varcont)
                    else:
                        self.flevel = self.contlevstr[0]

                    float(self.flevel)
                    self.contlevlist = [float(self.flevel)]

                except:
                    self.contlevlist = 5
                else:
                    for j in range(1, len(self.contlevstr)):
                        self.contlevlist.append(float(self.contlevstr[j]))

                self.cs1 = self.a.contour(self.xcont,
                                          self.ycont,
                                          self.varcont,
                                          self.contlevlist,
                                          colors="w")
                self.a.clabel(self.cs1, inline=True)

        if self.arrowvar.get() == 1:
            try:
                self.plarr.get() != "None"
            except KeyError:
                print "Specify the variable for plotting the arrow"
            else:
                self.drawarrow()
                self.a.quiver(self.xcong,
                              self.ycong,
                              self.xveccong,
                              self.yveccong,
                              color='w')

        self.a.set_xlabel(self.xlb.get())
        self.a.set_ylabel(self.ylb.get())
        self.canvas.show()
        print time.time() - tdum

    def getvarrange(self):
        try:
            float(self.varmin.get())
        except:
            if self.polarvar.get() != 1:
                self.varminval = min(self.var)
            else:
                self.varminval = min(
                    self.SphData[self.myvar][self.isnotnan].flat)  #self.minPl
        else:
            self.varminval = float(self.varmin.get())

        try:
            float(self.varmax.get())
        except:
            if self.polarvar.get() != 1:
                self.varmaxval = max(self.var)
            else:
                self.varmaxval = max(
                    self.SphData[self.myvar][self.isnotnan].flat)  #self.maxPl
        else:
            self.varmaxval = float(self.varmax.get())

        return [self.varminval, self.varmaxval]

    def getxaxisrange(self):
        try:
            float(self.xrmin.get())
        except:
            if self.polarvar.get() != 1:
                self.xminval = min(self.x)
            else:
                self.xminval = min(self.R.flat)
        else:
            self.xminval = float(self.xrmin.get())

        try:
            float(self.xrmax.get())
        except:
            if self.polarvar.get() != 1:
                self.xmaxval = max(self.x)
            else:
                self.xmaxval = max(self.R.flat)
        else:
            self.xmaxval = float(self.xrmax.get())

        return [self.xminval, self.xmaxval]

    def getyaxisrange(self):
        try:
            float(self.yrmin.get())
        except:
            if self.polarvar.get() != 1:
                self.yminval = min(self.y)
            else:
                self.yminval = min(self.Z.flat)
        else:
            self.yminval = float(self.yrmin.get())

        try:
            float(self.yrmax.get())
        except:
            if self.polarvar.get() != 1:
                self.ymaxval = max(self.y)
            else:
                self.ymaxval = max(self.Z.flat)
        else:
            self.ymaxval = float(self.yrmax.get())

        return [self.yminval, self.ymaxval]

    def getplotvar(self):
        self.sucess = False
        if self.logvar.get() == 1:
            self.var = log10(self.D.__getattribute__(self.myvar))
        else:
            self.var = self.D.__getattribute__(self.myvar)

        if self.Geom == '1D':
            self.x = self.D.x1
            self.sucess = True
        else:
            if self.slicename == "Along x1":
                self.x = self.D.x1
                if self.grid_dict["n3"] == 1:
                    try:
                        int(self.ex2.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x2 cut"
                    else:
                        self.var = self.var[:, int(self.ex2.get())]
                        self.sucess = True
                else:
                    try:
                        int(self.ex2.get().strip().split()[0])
                        int(self.ex3.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x2 or x3 cut"
                    else:
                        self.var = self.var[:,
                                            int(self.ex2.get()),
                                            int(self.ex3.get())]
                        self.sucess = True

            elif self.slicename == "Along x2":
                self.x = self.D.x2
                if self.grid_dict["n3"] == 1:
                    try:
                        int(self.ex1.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x1 cut"
                    else:
                        self.var = self.var[int(self.ex1.get()), :]
                        self.sucess = True
                else:
                    try:
                        int(self.ex1.get().strip().split()[0])
                        int(self.ex3.get().strip().split()[0])
                    except (ValueError, IndexError):
                        print "Specify the value of x1 or x3 cut"
                    else:
                        self.var = self.var[int(self.ex1.get()), :,
                                            int(self.ex3.get())]
                        self.sucess = True

            else:
                self.x = self.D.x3
                try:
                    int(self.ex1.get().strip().split()[0])
                    int(self.ex2.get().strip().split()[0])
                except (ValueError, IndexError):
                    print "Specify the value of x1 or x2 cut"
                else:
                    self.var = self.var[int(self.ex1.get()),
                                        int(self.ex2.get()), :]
                    self.sucess = True

        return self.sucess

    def getsurfvar(self):
        self.sucess = False
        if self.logvar.get() == 1:
            self.var = log10(self.D.__getattribute__(self.myvar))
        else:
            self.var = self.D.__getattribute__(self.myvar)

        if self.slicename == "Along x1-x2":
            self.x = self.D.x1
            self.y = self.D.x2
            if self.grid_dict["n3"] == 1:
                self.var = self.var[:, :].T
                self.sucess = True
            else:
                try:
                    int(self.ex3.get().strip().split()[0])
                except (ValueError, IndexError):
                    print "Specify the value of x3 cut"
                else:
                    self.var = self.var[:, :, int(self.ex3.get())].T
                    self.sucess = True

        elif self.slicename == "Along x2-x3":
            self.x = self.D.x2
            self.y = self.D.x3
            try:
                int(self.ex1.get().strip().split()[0])
            except (ValueError, IndexError):
                print "Specify the value of x1 cut"
            else:
                self.var = self.var[int(self.ex1.get()), :, :].T
                self.sucess = True
        else:
            self.x = self.D.x1
            self.y = self.D.x3
            try:
                int(self.ex2.get().strip().split()[0])
            except (ValueError, IndexError):
                print "Specify the value of x2 cut"
            else:
                self.var = self.var[:, int(self.ex2.get()), :].T
                self.sucess = True

        return self.sucess

    def drawpolar(self):
        self.sucess = False
        if self.slicename == "Along x1-x2":
            if self.grid_dict["n3"] == 1:
                self.R, self.Z, self.SphData = self.I.getSphData(
                    self.D, w_dir=self.wdir, rphi=False)
                self.sucess = True
            else:
                try:
                    int(self.ex3.get().strip().split()[0])
                except (ValueError, IndexError):
                    print "Specify the value of x3 cut"
                else:
                    self.R, self.Z, self.SphData = self.I.getSphData(
                        self.D,
                        w_dir=self.wdir,
                        rphi=False,
                        x3cut=int(self.ex3.get()))
                    self.sucess = True

        if self.slicename == "Along x3-x1":
            try:
                int(self.ex2.get().strip().split()[0])
            except (ValueError, IndexError):
                print "Specify the value of x2 cut"
            else:
                self.R, self.Z, self.SphData = self.I.getSphData(
                    self.D,
                    w_dir=self.wdir,
                    rphi=True,
                    x2cut=int(self.ex2.get()))
                self.sucess = True

        if self.sucess == True:
            self.extent = (min(self.R.flat), max(self.R.flat),
                           min(self.Z.flat), max(self.Z.flat))
            self.dRR = max(self.R.flat) - min(self.R.flat)
            self.dZZ = max(self.Z.flat) - min(self.Z.flat)

            self.isnotnan = -isnan(self.SphData[self.myvar])
            self.maxPl = max(self.SphData[self.myvar][self.isnotnan].flat)
            self.minPl = min(self.SphData[self.myvar][self.isnotnan].flat)
            self.normrange = False
            if self.minPl < 0:
                self.normrange = True
            if self.maxPl > -self.minPl:
                self.minPl = -self.maxPl
            else:
                self.maxPl = -self.minPl
            if (self.normrange and self.myvar != 'rho' and self.myvar != 'pr'):
                self.SphData[self.myvar][-1][-1] = self.maxPl
                self.SphData[self.myvar][-1][-2] = self.minPl
            if self.logvar.get() == 1:
                self.SphData[self.myvar] = log10(self.SphData[self.myvar])

        return self.sucess

    def drawcontour(self):
        if self.polarvar.get() != 1:
            if self.slicename == "Along x1-x2":
                self.xcont = self.D.x1
                self.ycont = self.D.x2
                self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T, self.D.x2.T)
                if self.grid_dict["n3"] == 1:
                    if self.plcont.get() == 'x1*A3':
                        self.varcont = self.Xmesh * (self.D.A3.T)
                    elif self.plcont.get() == 'x1*b3':
                        self.varcont = self.Xmesh * (self.D.b3.T)
                    else:
                        self.varcont = self.D.__getattribute__(
                            self.plcont.get())[:, :].T
                else:
                    if self.plcont.get() == 'x1*A3':
                        self.varcont = self.Xmesh * (
                            self.D.A3[:, :, int(self.ex3.get())].T)
                    elif self.plcont.get() == 'x1*b3':
                        self.varcont = self.Xmesh * (
                            self.D.b3[:, :, int(self.ex3.get())].T)
                    else:
                        self.varcont = self.D.__getattribute__(
                            self.plcont.get())[:, :, int(self.ex3.get())].T

            elif self.slicename == "Along x2-x3":
                self.xcont = self.D.x2
                self.ycont = self.D.x3
                self.varcont = self.D.__getattribute__(
                    self.plcont.get())[int(self.ex1.get()), :, :].T
            else:
                self.xcont = self.D.x1
                self.ycont = self.D.x3
                self.varcont = self.D.__getattribute__(
                    self.plcont.get())[:, int(self.ex2.get()), :].T
        else:
            self.xcont = self.R
            self.ycont = self.Z
            if self.plcont.get() == 'x1*A3':
                self.varcont = self.R * (self.SphData['A3'])
            elif self.plcont.get() == 'x1*b3':
                self.varcont = self.R * (self.SphData['b3'])
            else:
                if self.logvar.get() == 1 and self.plcont.get() == self.myvar:
                    self.varcont = 10**(self.SphData[self.plcont.get()])
                else:
                    self.varcont = self.SphData[self.plcont.get()]

    def drawarrow(self):
        if self.polarvar.get() != 1:
            if self.slicename == "Along x1-x2":
                self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T, self.D.x2.T)
                self.xcong = self.Tool.congrid(self.Xmesh,
                                               2 * (int(self.arrspb.get()), ),
                                               method='linear')
                self.ycong = self.Tool.congrid(self.Ymesh,
                                               2 * (int(self.arrspb.get()), ),
                                               method='linear')
                if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm':
                    if self.grid_dict["n3"] == 1:
                        self.vel1 = self.D.v1[:, :].T
                        self.vel2 = self.D.v2[:, :].T
                    else:
                        self.vel1 = self.D.v1[:, :, int(self.ex3.get())].T
                        self.vel2 = self.D.v2[:, :, int(self.ex3.get())].T

                    self.xveccong = self.Tool.congrid(
                        self.vel1,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.yveccong = self.Tool.congrid(
                        self.vel2,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Vp_norm':
                        self.xveccong = self.xveccong / self.normVp
                        self.yveccong = self.yveccong / self.normVp
                if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm':
                    if self.grid_dict["n3"] == 1:
                        self.mag1 = self.D.b1[:, :].T
                        self.mag2 = self.D.b2[:, :].T
                    else:
                        self.mag1 = self.D.b1[:, :, int(self.ex3.get())].T
                        self.mag2 = self.D.b2[:, :, int(self.ex3.get())].T

                    self.xveccong = self.Tool.congrid(
                        self.mag1,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.yveccong = self.Tool.congrid(
                        self.mag2,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Bp_norm':
                        self.xveccong = self.xveccong / self.normVp
                        self.yveccong = self.yveccong / self.normVp

            elif self.slicename == "Along x2-x3":
                self.Xmesh, self.Ymesh = meshgrid(self.D.x2.T, self.D.x3.T)
                self.xcong = self.Tool.congrid(self.Xmesh,
                                               2 * (int(self.arrspb.get()), ),
                                               method='linear')
                self.ycong = self.Tool.congrid(self.Ymesh,
                                               2 * (int(self.arrspb.get()), ),
                                               method='linear')
                if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm':
                    self.vel1 = self.D.v2[int(self.ex1.get()), :, :].T
                    self.vel2 = self.D.v3[int(self.ex1.get()), :, :].T
                    self.xveccong = self.Tool.congrid(
                        self.vel1,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.yveccong = self.Tool.congrid(
                        self.vel2,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Vp_norm':
                        self.xveccong = self.xveccong / self.normVp
                        self.yveccong = self.yveccong / self.normVp
                if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm':
                    self.mag1 = self.D.b2[int(self.ex1.get()), :, :].T
                    self.mag2 = self.D.b3[int(self.ex1.get()), :, :].T
                    self.xveccong = self.Tool.congrid(
                        self.mag1,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.yveccong = self.Tool.congrid(
                        self.mag2,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Bp_norm':
                        self.xveccong = self.xveccong / self.normVp
                        self.yveccong = self.yveccong / self.normVp
            else:
                self.Xmesh, self.Ymesh = meshgrid(self.D.x1.T, self.D.x3.T)
                self.xcong = self.Tool.congrid(self.Xmesh,
                                               2 * (int(self.arrspb.get()), ),
                                               method='linear')
                self.ycong = self.Tool.congrid(self.Ymesh,
                                               2 * (int(self.arrspb.get()), ),
                                               method='linear')
                if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm':
                    self.vel1 = self.D.v1[:, int(self.ex2.get()), :].T
                    self.vel2 = self.D.v3[:, int(self.ex2.get()), :].T
                    self.xveccong = self.Tool.congrid(
                        self.vel1,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.yveccong = self.Tool.congrid(
                        self.vel2,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Vp_norm':
                        self.xveccong = self.xveccong / self.normVp
                        self.yveccong = self.yveccong / self.normVp
                if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm':
                    self.mag1 = self.D.b1[:, int(self.ex2.get()), :].T
                    self.mag2 = self.D.b3[:, int(self.ex2.get()), :].T
                    self.xveccong = self.Tool.congrid(
                        self.mag1,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.yveccong = self.Tool.congrid(
                        self.mag2,
                        2 * (int(self.arrspb.get()), ),
                        method='linear')
                    self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                    if self.plarr.get() == 'Bp_norm':
                        self.xveccong = self.xveccong / self.normVp
                        self.yveccong = self.yveccong / self.normVp
        else:
            self.xcong = self.Tool.congrid(self.R,
                                           2 * (int(self.arrspb.get()), ),
                                           method='linear')
            self.ycong = self.Tool.congrid(self.Z,
                                           2 * (int(self.arrspb.get()), ),
                                           method='linear')
            if self.plarr.get() == 'Vp' or self.plarr.get() == 'Vp_norm':
                if self.slicename == "Along x1-x2":
                    self.vel1 = self.SphData['v1c']
                    self.vel2 = self.SphData['v2c']
                else:
                    self.vel1 = self.SphData['v1c']
                    self.vel2 = self.SphData['v3c']

                self.xveccong = self.Tool.congrid(self.vel1,
                                                  2 *
                                                  (int(self.arrspb.get()), ),
                                                  method='linear')
                self.yveccong = self.Tool.congrid(self.vel2,
                                                  2 *
                                                  (int(self.arrspb.get()), ),
                                                  method='linear')
                self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                if self.plarr.get() == 'Vp_norm':
                    self.xveccong = self.xveccong / self.normVp
                    self.yveccong = self.yveccong / self.normVp
            if self.plarr.get() == 'Bp' or self.plarr.get() == 'Bp_norm':

                if self.slicename == "Along x1-x2":
                    self.mag1 = self.SphData['b1c']
                    self.mag2 = self.SphData['b2c']
                else:
                    self.mag1 = self.SphData['b1c']
                    self.mag2 = self.SphData['b3c']

                self.xveccong = self.Tool.congrid(self.mag1,
                                                  2 *
                                                  (int(self.arrspb.get()), ),
                                                  method='linear')
                self.yveccong = self.Tool.congrid(self.mag2,
                                                  2 *
                                                  (int(self.arrspb.get()), ),
                                                  method='linear')
                self.normVp = sqrt(self.xveccong**2 + self.yveccong**2)
                if self.plarr.get() == 'Bp_norm':
                    self.xveccong = self.xveccong / self.normVp
                    self.yveccong = self.yveccong / self.normVp

    def epssave(self):
        self.f.savefig(self.myvar + '_' + self.enstep.get() + '.eps')

    def pngsave(self):
        self.f.savefig(self.myvar + '_' + self.enstep.get() + '.png')

    def pdfsave(self):
        self.f.savefig(self.myvar + '_' + self.enstep.get() + '.pdf')

    def jpgsave(self):
        self.f.savefig(self.myvar + '_' + self.enstep.get() + '.jpg')
Exemple #33
0
    def plot_on_map(self, param='Speed (OBD)', detail=1, cmap='hot'):
        """@deprecated Plots a trace parameter on a map."""
        lats, lngs = self.df['Latitude'], self.df['Longitude']
        # plot longitude vs latitude using speed as color
        track_bounds = Pin(np.min(lats),
                           np.min(lngs)), Pin(np.max(lats), np.max(lngs))
        track_center = Pin(np.median(lats), np.median(lngs))

        fig = Figure()  # create new figure outside pyplot
        # A canvas must be manually attached to the figure (pyplot would automatically
        # do it).  This is done by instantiating the canvas with the figure as
        # argument.
        FigureCanvas(fig)
        ax = fig.add_subplot(111)
        # ax.set_aspect('equal')

        # plot the trace as latitude, longitude scatter with 'param' as color
        colors = self.df[param]  # .values
        self.df.plot(kind='scatter',
                     x='Longitude',
                     y='Latitude',
                     ax=ax,
                     c=colors,
                     cmap=cmap)

        # delete the colorbar created by dataframe.plot
        if len(fig.axes) > 1:
            fig.delaxes(fig.axes[-1])  # delete the last one

        # save limits and use them to get a map
        xlim = ax.get_xlim()
        ylim = ax.get_ylim()

        width = np.ptp(xlim)
        height = np.ptp(ylim)

        self.aspect = height / width

        # fig.set_dpi(100)
        screen_width = 15.
        size = (screen_width, screen_width * self.aspect)
        fig.set_size_inches(size)

        # make lat, lng pins for bounds to get_bounded_map
        # get a map matching the bounds of the plot
        sw = Pin(ylim[0], xlim[0])
        ne = Pin(ylim[1], xlim[1])
        bounds = (sw, ne)
        mapfield = Mapfield(bounds=bounds, detail=detail)
        mapimage = mapfield.image

        ext = *xlim, *ylim  # left, right, bottom, top
        ax.imshow(mapimage,
                  zorder=0,
                  extent=ext,
                  aspect='auto',
                  interpolation='bicubic')

        # plt.axis('off')

        return fig
class NumberTracing(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent

        #Variables for ROIframe
        self.varX1 = tk.StringVar()
        self.varY1 = tk.StringVar()
        self.varX2 = tk.StringVar()
        self.varY2 = tk.StringVar()

        self.varX1.set("0")
        self.varY1.set("0")
        self.varX2.set("0")
        self.varY2.set("0")

        #Variables for the tesseract loop
        self.values = []
        self.times = []
        self.running = False
        self.idle = tk.DoubleVar()
        self.idle.set(1.0)
        self.i = 0
        self.memory = numpy.nan
        self.latestDiff = 0.
        self.shortMem = []

        #Frames
        self.left = tk.Frame(self.parent, borderwidth=1, relief="solid")
        self.right = tk.Frame(self.parent, borderwidth=1, relief="solid")
        self.righttop = tk.Frame(self.right, borderwidth=1, relief="solid")
        self.rightmiddle = tk.Frame(self.right, borderwidth=1, relief="solid")
        self.rightbottom = tk.Frame(self.right, borderwidth=1, relief="solid")

        #Labels
        self.delimiterL = tk.Label(self.rightmiddle, text="Delimiter:")
        self.idleL = tk.Label(self.rightmiddle, text="Time delay:")

        #Buttons
        ROIb = tk.Button(self.righttop,
                         text="Define ROI",
                         command=lambda: self.start_klickYourROI(None))
        saveROIb = tk.Button(self.righttop,
                             text="Save ROI",
                             command=lambda: self.start_saveROI(None))
        loadROIb = tk.Button(self.righttop,
                             text="Load ROI",
                             command=lambda: self.start_loadROI(None))
        runb = tk.Button(self.rightmiddle,
                         text="Start",
                         bg="LightBlue1",
                         command=lambda: self.start_run(None))
        stopb = tk.Button(self.rightmiddle,
                          text="Stop",
                          bg="orange2",
                          command=lambda: self.start_stop(None))
        clearb = tk.Button(self.rightmiddle,
                           text="Clear",
                           command=lambda: self.start_clear(None))
        lastminb = tk.Button(self.rightmiddle,
                             text="Last Minute",
                             command=lambda: self.start_lastminute(None))
        saveb = tk.Button(self.rightmiddle,
                          text="Save Graph",
                          command=lambda: self.start_savegraph(None))

        #Entry fields
        self.delimiterE = tk.Entry(master=self.rightmiddle)
        self.idleE = tk.Entry(master=self.rightmiddle)

        #Figures
        self.fig = Figure(figsize=(2, 1))
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.rightbottom)

        self.figleft = Figure(figsize=(6, 2))
        self.canvasleft = FigureCanvasTkAgg(self.figleft, master=self.left)

        #Opening image
        image = cv2.imread("dogwithfish.jpg")
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        self.subfleft = self.figleft.add_subplot(111)
        self.subfleft.axis('off')
        self.subfleft.imshow(image)

        #Checkboxes
        self.difference = tk.IntVar()
        self.totalordifferenceCB = tk.Checkbutton(self.rightmiddle,
                                                  text="Difference?",
                                                  variable=self.difference)

        #Packing it all
        self.left.pack(side="left", expand=True, fill="both")
        self.right.pack(side="right", expand=True, fill="both")
        self.righttop.pack(side="top", expand=True, fill="both")
        self.rightbottom.pack(side="bottom", expand=True, fill="both")
        self.rightmiddle.pack(side="bottom", expand=True, fill="both")
        self.canvas.get_tk_widget().pack(fill="both", expand=True)
        self.canvasleft.get_tk_widget().pack(fill="both", expand=True)

        ROIb.pack(fill=tk.X, padx=2, pady=2)
        saveROIb.pack(fill=tk.X, padx=2, pady=2)
        loadROIb.pack(fill=tk.X, padx=2, pady=2)

        self.delimiterL.pack(fill=tk.X, padx=2, pady=2)
        self.delimiterE.pack(fill=tk.X, padx=2, pady=2)
        self.idleL.pack(fill=tk.X, padx=2, pady=2)
        self.idleE.pack(fill=tk.X, padx=2, pady=2)

        runb.pack(fill=tk.X, padx=2, pady=2)
        stopb.pack(fill=tk.X, padx=2, pady=2)
        clearb.pack(fill=tk.X, padx=2, pady=2)
        lastminb.pack(fill=tk.X, padx=2, pady=2)

        self.totalordifferenceCB.pack(fill=tk.X, padx=2, pady=2)
        saveb.pack(fill=tk.X, padx=2, pady=2)

    #Functions
    def queryMousePosition(self):
        pt = POINT()
        windll.user32.GetCursorPos(byref(pt))
        return pt.x, pt.y

    #Button Functions
    def klickYourROI(self):
        klicksdone = 0
        state_left = win32api.GetKeyState(0x01)
        print("Klick upper left!")

        while klicksdone < 1:
            a = win32api.GetKeyState(0x01)
            if a != state_left:  # Button state changed
                state_left = a
                if a < 0:
                    print(' ')
                else:
                    #print('Left Button Released1')
                    x1, y1 = self.queryMousePosition()
                    klicksdone = 1

        print("Klick lower right!")
        while klicksdone < 2:
            a = win32api.GetKeyState(0x01)
            if a != state_left:  # Button state changed
                state_left = a
                if a < 0:
                    print(' ')
                else:
                    #print('Left Button Released2')
                    x2, y2 = self.queryMousePosition()
                    klicksdone = 2

        self.varX1.set(str(x1))
        self.varY1.set(str(y1))
        self.varX2.set(str(x2))
        self.varY2.set(str(y2))

        self.parent.update_idletasks()
        print(x1, y1, x2, y2)
        return 0

    def start_klickYourROI(self, event):
        global ROI_thread
        ROI_thread = threading.Thread(target=self.klickYourROI)
        ROI_thread.deamon = True
        ROI_thread.start()

    def saveROI(self):
        with open("ROI.txt", "w") as ROIfile:
            ROIfile.write("{}\n{}\n{}\n{}".format(self.varX1.get(),
                                                  self.varY1.get(),
                                                  self.varX2.get(),
                                                  self.varY2.get()))

    def start_saveROI(self, event):
        self.saveROI()

    def loadROI(self):
        with open("ROI.txt", "r") as ROIfile:
            data = ROIfile.read().splitlines()

        self.varX1.set(data[0])
        self.varY1.set(data[1])
        self.varX2.set(data[2])
        self.varY2.set(data[3])

        image = PIL.ImageGrab.grab(bbox=(int(self.varX1.get()),
                                         int(self.varY1.get()),
                                         int(self.varX2.get()),
                                         int(self.varY2.get())))

        subf = self.fig.add_subplot(111)
        subf.clear()
        subf.axis('off')
        subf.imshow(image)

        self.canvas.draw()

    def start_loadROI(self, event):
        self.loadROI()

    def stop(self):
        self.running = False
        print("Stopped!")

    def start_stop(self, event):
        self.stop()

    def run(self):
        print("Running!")
        T = float(self.idleE.get())
        print(T)
        splitting = True
        delimiter = self.delimiterE.get()
        if delimiter == "":
            splitting = False
        print(delimiter)

        if self.difference.get() == 1:
            mode = "Difference"
        else:
            mode = "Total"

        #while self.running == True:
        startt = time.time()
        image = PIL.ImageGrab.grab(bbox=(int(self.varX1.get()),
                                         int(self.varY1.get()),
                                         int(self.varX2.get()),
                                         int(self.varY2.get())))

        subf = self.fig.add_subplot(111)
        subf.clear()
        subf.axis('off')
        subf.imshow(image)
        self.canvas.draw()

        opencvImage = cv2.cvtColor(numpy.array(image), cv2.COLOR_BGR2GRAY)

        #use tesseract to read the numbers from the chosen frame
        results = tes.image_to_string(opencvImage)
        results = mergeInCaseOfSplitted(results)
        results = results.replace(" ", "")

        if splitting == True:
            try:
                splitresults = results.split(
                    delimiter
                )  #Split the string at the commata and match together
                number = ""
                for j in range(len(splitresults)):
                    number += splitresults[j]
                print(splitresults, number, self.i)
                number = float(number)
            except:  #Problem with the splitting
                print("Result is not float!")
                number = numpy.nan

        else:
            print(results)
            try:
                number = float(results)
                print(number)
            except:
                number = numpy.nan
                print("Result is not float!")

        #Append Values to arrays and check for potential problems
        self.times.append(int(self.i) * T)

        if mode == "Difference":
            print("Mode is Difference!")
            try:
                if self.i < 2:  #for the first number there is no earlier number, so set to NaN
                    self.shortMem.append(number)
                    self.values.append(numpy.nan)
                    self.memory = numpy.nan
                    if self.i == 1:
                        self.latestDiff = self.shortMem[1] - self.shortMem[0]
                else:
                    if number - self.memory < 0.0001:  #adjust for display and screenshot not synched (python too fast)
                        self.values.append(self.latestDiff)
                    else:
                        self.latestDiff = number - self.memory  #if everything is fine just add the difference between current and last
                        self.values.append(self.latestDiff)
            except Exception as e:  #add NaN if anything goes wrong
                self.values.append(numpy.nan)
                print(e)

            try:
                self.memory = number
            except:
                self.memory = numpy.nan

            print("Memory = {}".format(self.memory))

        if mode == "Total":
            print("Mode is Total!")
            try:
                if self.i < 1:  #for the first number there is no earlier number, so set to NaN
                    self.values.append(numpy.nan)
                else:
                    self.values.append(number)
            except:  #add NaN if anything goes wrong
                self.values.append(numpy.nan)

        self.figleft.delaxes(self.subfleft)
        self.subfleft = self.figleft.add_subplot(111)
        self.subfleft.clear()
        self.subfleft.set_title("Behaviour of Variable")
        self.subfleft.set_xlabel("Time [s]")
        self.subfleft.set_ylabel("Value")
        self.subfleft.plot(numpy.array(self.times), numpy.array(self.values))
        self.subfleft.grid()
        self.canvasleft.draw()

        endt = time.time()
        diff = endt - startt
        print(diff)
        print(T)
        print(threading.active_count())
        try:
            time.sleep(T - diff)
        except Exception as e:
            print(e)
            print("Issue with time delay.")

        self.i += 1

        if self.running == True:
            self.after(1, self.run)

    def start_run(self, event):
        self.running = True
        self.run()

    def clear(self):
        self.times = []
        self.values = []
        self.i = 0

        subfleft = self.figleft.add_subplot(111)
        subfleft.clear()

    def start_clear(self, event):
        self.clear()

    def lastminute(self):
        #Calculate how many indicees have to be cut off to get one minute:
        #Number of indicees is 60 seconds devided by the repetition rate T
        indicees = int(60. / float(self.idleE.get()))
        self.times = self.times[-1 * indicees:-1]
        self.values = self.values[-1 * indicees:-1]

    def start_lastminute(self, event):
        self.lastminute()

    def savegraph(self):
        f = open('countsOverTime.txt', 'w')
        for j in range(len(self.values)):
            f.write(str(self.times[j]) + '\t' + str(self.values[j]) + '\n')
        f.close()

    def start_savegraph(self, event):
        self.savegraph()
Exemple #35
0
class TimelineFrame(wx.Frame):
    """The main frame of the application"""
    def __init__(self, parent):
        wx.Frame.__init__(self,
                          parent,
                          id=wx.ID_ANY,
                          title=_("GRASS GIS Timeline Tool"))

        tgis.init(True)
        self.datasets = []
        self.timeData = {}
        self._layout()
        self.temporalType = None
        self.unit = None
        # We create a database interface here to speedup the GUI
        self.dbif = tgis.SQLDatabaseInterfaceConnection()
        self.dbif.connect()
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, event):
        """Close the database interface and stop the messenger and C-interface
           subprocesses.
        """
        if self.dbif.connected is True:
            self.dbif.close()
        tgis.stop_subprocesses()
        self.Destroy()

    def _layout(self):
        """Creates the main panel with all the controls on it:
             * mpl canvas
             * mpl navigation toolbar
             * Control panel for interaction
        """
        self.panel = wx.Panel(self)

        # Create the mpl Figure and FigCanvas objects.
        # 5x4 inches, 100 dots-per-inch
        #
        # color =  wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
        self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1))
        self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig)
        # axes are initialized later
        self.axes2d = None
        self.axes3d = None

        # Create the navigation toolbar, tied to the canvas
        #
        self.toolbar = NavigationToolbar(self.canvas)

        #
        # Layout
        #

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
        self.vbox.Add(self.toolbar, 0, wx.EXPAND)
        self.vbox.AddSpacer(10)

        gridSizer = wx.GridBagSizer(hgap=5, vgap=5)

        self.datasetSelect = gselect.Select(parent=self.panel,
                                            id=wx.ID_ANY,
                                            size=globalvar.DIALOG_GSELECT_SIZE,
                                            type='stds',
                                            multiple=True)
        self.drawButton = Button(self.panel, id=wx.ID_ANY, label=_("Draw"))
        self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw)
        self.helpButton = Button(self.panel, id=wx.ID_ANY, label=_("Help"))
        self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp)
        self.view3dCheck = wx.CheckBox(
            self.panel,
            id=wx.ID_ANY,
            label=_("3D plot of spatio-temporal extents"))
        self.view3dCheck.Bind(wx.EVT_CHECKBOX, self.OnRedraw)
        if not check_version(1, 0, 0):
            self.view3dCheck.SetLabel(
                _("3D plot of spatio-temporal extents "
                  "(matplotlib >= 1.0.0)"))
            self.view3dCheck.Disable()

        gridSizer.Add(StaticText(self.panel,
                                 id=wx.ID_ANY,
                                 label=_("Select space time dataset(s):")),
                      pos=(0, 0),
                      flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
        gridSizer.Add(self.datasetSelect, pos=(1, 0), flag=wx.EXPAND)
        gridSizer.Add(self.drawButton, pos=(1, 1), flag=wx.EXPAND)
        gridSizer.Add(self.helpButton, pos=(1, 2), flag=wx.EXPAND)
        gridSizer.Add(self.view3dCheck,
                      pos=(2, 0),
                      flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)

        self.vbox.Add(gridSizer,
                      proportion=0,
                      flag=wx.EXPAND | wx.ALL,
                      border=10)

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

    def _getData(self, timeseries):
        """Load data and read properties"""
        self.timeData = {}
        mode = None
        unit = None

        for series in timeseries:
            name = series[0] + '@' + series[1]
            etype = series[2]
            sp = tgis.dataset_factory(etype, name)
            if not sp.is_in_db(dbif=self.dbif):
                GError(
                    self,
                    message=_("Dataset <%s> not found in temporal database") %
                    (name))
                return

            sp.select(dbif=self.dbif)

            self.timeData[name] = {}
            self.timeData[name]['elementType'] = series[2]
            self.timeData[name]['temporalType'] = sp.get_temporal_type(
            )  # abs/rel

            if mode is None:
                mode = self.timeData[name]['temporalType']
            elif self.timeData[name]['temporalType'] != mode:
                GError(parent=self,
                       message=_(
                           "Datasets have different temporal type "
                           "(absolute x relative), which is not allowed."))
                return

            # check topology
            maps = sp.get_registered_maps_as_objects(dbif=self.dbif)
            self.timeData[name]['validTopology'] = sp.check_temporal_topology(
                maps=maps, dbif=self.dbif)

            self.timeData[name]['temporalMapType'] = sp.get_map_time(
            )  # point/interval
            self.timeData[name]['unit'] = None  # only with relative
            if self.timeData[name]['temporalType'] == 'relative':
                start, end, self.timeData[name]['unit'] = sp.get_relative_time(
                )
                if unit is None:
                    unit = self.timeData[name]['unit']
                elif self.timeData[name]['unit'] != unit:
                    GError(
                        self,
                        _("Datasets have different time unit which is not allowed."
                          ))
                    return

            self.timeData[name]['start_datetime'] = []
            # self.timeData[name]['start_plot'] = []
            self.timeData[name]['end_datetime'] = []
            # self.timeData[name]['end_plot'] = []
            self.timeData[name]['names'] = []
            self.timeData[name]['north'] = []
            self.timeData[name]['south'] = []
            self.timeData[name]['west'] = []
            self.timeData[name]['east'] = []

            columns = ','.join([
                'name', 'start_time', 'end_time', 'north', 'south', 'west',
                'east'
            ])

            rows = sp.get_registered_maps(columns=columns,
                                          where=None,
                                          order='start_time',
                                          dbif=self.dbif)
            if not rows:
                GError(parent=self,
                       message=_("Dataset <{name}> is empty").format(
                           name=series[0] + '@' + series[1]))
                return
            for row in rows:
                mapName, start, end, north, south, west, east = row
                self.timeData[name]['start_datetime'].append(start)
                self.timeData[name]['end_datetime'].append(end)
                self.timeData[name]['names'].append(mapName)
                self.timeData[name]['north'].append(north)
                self.timeData[name]['south'].append(south)
                self.timeData[name]['west'].append(west)
                self.timeData[name]['east'].append(east)

        self.temporalType = mode
        self.unit = unit

    def _draw3dFigure(self):
        """Draws 3d view (spatio-temporal extents).


        Only for matplotlib versions >= 1.0.0.
        Earlier versions cannot draw time ticks and alpha
        and it has a slightly different API.
        """
        self.axes3d.clear()
        self.axes3d.grid(False)
        # self.axes3d.grid(True)
        if self.temporalType == 'absolute':
            convert = mdates.date2num
        else:
            convert = lambda x: x

        colors = cycle(COLORS)
        plots = []
        for name in self.datasets:
            name = name[0] + '@' + name[1]
            startZ = convert(self.timeData[name]['start_datetime'])
            mapType = self.timeData[name]['temporalMapType']
            if mapType == 'interval':
                dZ = convert(self.timeData[name]['end_datetime']) - startZ

            else:
                dZ = [0] * len(startZ)

            startX = self.timeData[name]['west']
            dX = self.timeData[name]['east'] - np.array(startX)
            startY = self.timeData[name]['south']
            dY = self.timeData[name]['north'] - np.array(startY)

            color = next(colors)
            plots.append(
                self.axes3d.bar3d(startX,
                                  startY,
                                  startZ,
                                  dX,
                                  dY,
                                  dZ,
                                  color=color,
                                  alpha=ALPHA))

        params = grass.read_command('g.proj', flags='g')
        params = grass.parse_key_val(params)
        if 'unit' in params:
            self.axes3d.set_xlabel(_("X [%s]") % params['unit'])
            self.axes3d.set_ylabel(_("Y [%s]") % params['unit'])
        else:
            self.axes3d.set_xlabel(_("X"))
            self.axes3d.set_ylabel(_("Y"))

        if self.temporalType == 'absolute':
            if check_version(1, 1, 0):
                self.axes3d.zaxis_date()
        self.axes3d.set_zlabel(_('Time'))
        self.axes3d.mouse_init()
        self.canvas.draw()

    def _draw2dFigure(self):
        """Draws 2D plot (temporal extents)"""
        self.axes2d.clear()
        self.axes2d.grid(True)
        if self.temporalType == 'absolute':
            convert = mdates.date2num
        else:
            convert = lambda x: x

        colors = cycle(COLORS)

        yticksNames = []
        yticksPos = []
        plots = []
        lookUp = LookUp(self.timeData)
        for i, name in enumerate(self.datasets):
            # just name; with mapset it would be long
            yticksNames.append(name[0])
            name = name[0] + '@' + name[1]
            yticksPos.append(i)
            barData = []
            pointData = []
            mapType = self.timeData[name]['temporalMapType']

            start = convert(self.timeData[name]['start_datetime'])
            # TODO: mixed
            if mapType == 'interval':
                end = convert(self.timeData[name]['end_datetime'])
                lookUpData = list(zip(start, end))
                duration = end - np.array(start)
                barData = list(zip(start, duration))
                lookUp.AddDataset(type_='bar',
                                  yrange=(i - 0.1, i + 0.1),
                                  xranges=lookUpData,
                                  datasetName=name)

            else:
                # self.timeData[name]['end_plot'] = None
                pointData = start
                lookUp.AddDataset(type_='point',
                                  yrange=i,
                                  xranges=pointData,
                                  datasetName=name)
            color = next(colors)
            if mapType == 'interval':
                plots.append(
                    self.axes2d.broken_barh(xranges=barData,
                                            yrange=(i - 0.1, 0.2),
                                            facecolors=color,
                                            edgecolor='black',
                                            alpha=ALPHA))
            else:
                plots.append(
                    self.axes2d.plot(pointData, [i] * len(pointData),
                                     marker='o',
                                     linestyle='None',
                                     color=color)[0])

        if self.temporalType == 'absolute':
            self.axes2d.xaxis_date()
            self.fig.autofmt_xdate()
            # self.axes2d.set_xlabel(_("Time"))
        else:
            self.axes2d.set_xlabel(_("Time [%s]") % self.unit)

        self.axes2d.set_yticks(yticksPos)
        self.axes2d.set_yticklabels(yticksNames)
        self.axes2d.set_ylim(min(yticksPos) - 1, max(yticksPos) + 1)

        # adjust xlim
        xlim = self.axes2d.get_xlim()
        padding = ceil((xlim[1] - xlim[0]) / 20.)
        self.axes2d.set_xlim(xlim[0] - padding, xlim[1] + padding)
        self.axes2d.set_axisbelow(True)

        self.canvas.draw()
        DataCursor(plots, lookUp, InfoFormat)

    def OnRedraw(self, event):
        """Required redrawing."""
        datasets = self.datasetSelect.GetValue().strip()
        if not datasets:
            return
        datasets = datasets.split(',')
        try:
            datasets = self._checkDatasets(datasets)
            if not datasets:
                return
        except GException as e:
            GError(parent=self, message=unicode(e), showTraceback=False)
            return

        self.datasets = datasets
        self._redraw()

    def _redraw(self):
        """Readraw data.

        Decides if to draw also 3D and adjusts layout if needed.
        """
        self._getData(self.datasets)

        # axes3d are physically removed
        if not self.axes2d:
            self.axes2d = self.fig.add_subplot(1, 1, 1)
        self._draw2dFigure()
        if check_version(1, 0, 0):
            if self.view3dCheck.IsChecked():
                self.axes2d.change_geometry(2, 1, 1)
                if not self.axes3d:
                    # do not remove this import - unused but it is required for
                    # 3D
                    from mpl_toolkits.mplot3d import Axes3D  # pylint: disable=W0611
                    self.axes3d = self.fig.add_subplot(2,
                                                       1,
                                                       2,
                                                       projection='3d')

                self.axes3d.set_visible(True)
                self._draw3dFigure()
            else:
                if self.axes3d:
                    self.fig.delaxes(self.axes3d)
                    self.axes3d = None
                self.axes2d.change_geometry(1, 1, 1)
                self.canvas.draw()

    def _checkDatasets(self, datasets):
        """Checks and validates datasets.

        Reports also type of dataset (e.g. 'strds').

        :return: (mapName, mapset, type)
        """
        validated = []
        tDict = tgis.tlist_grouped('stds', group_type=True, dbif=self.dbif)
        # nested list with '(map, mapset, etype)' items
        allDatasets = [[[(map, mapset, etype) for map in maps]
                        for etype, maps in six.iteritems(etypesDict)]
                       for mapset, etypesDict in six.iteritems(tDict)]
        # flatten this list
        if allDatasets:
            allDatasets = reduce(lambda x, y: x + y,
                                 reduce(lambda x, y: x + y, allDatasets))
            mapsets = tgis.get_tgis_c_library_interface().available_mapsets()
            allDatasets = [
                i
                for i in sorted(allDatasets, key=lambda l: mapsets.index(l[1]))
            ]

        for dataset in datasets:
            errorMsg = _("Space time dataset <%s> not found.") % dataset
            if dataset.find("@") >= 0:
                nameShort, mapset = dataset.split('@', 1)
                indices = [
                    n for n, (mapName, mapsetName,
                              etype) in enumerate(allDatasets)
                    if nameShort == mapName and mapsetName == mapset
                ]
            else:
                indices = [
                    n for n, (mapName, mapset, etype) in enumerate(allDatasets)
                    if dataset == mapName
                ]

            if len(indices) == 0:
                raise GException(errorMsg)
            elif len(indices) >= 2:
                dlg = wx.SingleChoiceDialog(
                    self,
                    message=_("Please specify the space time dataset <%s>." %
                              dataset),
                    caption=_("Ambiguous dataset name"),
                    choices=[("%(map)s@%(mapset)s: %(etype)s" % {
                        'map': allDatasets[i][0],
                        'mapset': allDatasets[i][1],
                        'etype': allDatasets[i][2]
                    }) for i in indices],
                    style=wx.CHOICEDLG_STYLE | wx.OK)
                if dlg.ShowModal() == wx.ID_OK:
                    index = dlg.GetSelection()
                    validated.append(allDatasets[indices[index]])
                else:
                    continue
            else:
                validated.append(allDatasets[indices[0]])

        return validated

    def OnHelp(self, event):
        RunCommand('g.manual', quiet=True, entry='g.gui.timeline')


#  interface

    def SetDatasets(self, datasets):
        """Set data"""
        if not datasets:
            return
        try:
            datasets = self._checkDatasets(datasets)
            if not datasets:
                return
        except GException as e:
            GError(parent=self, message=unicode(e), showTraceback=False)
            return
        self.datasets = datasets
        self.datasetSelect.SetValue(','.join(
            map(lambda x: x[0] + '@' + x[1], datasets)))
        self._redraw()

    def Show3D(self, show):
        """Show also 3D if possible"""
        if check_version(1, 0, 0):
            self.view3dCheck.SetValue(show)
Exemple #36
0
class PltWidget(tk.Frame):

    def __init__(self, parent):

        # inheritance
        tk.Frame.__init__(self, parent)
        self.parent = parent

        # figure init
        self.fig = Figure(figsize=FIG_SIZE)
        self.ax = self.fig.gca()

        # a tk.DrawingArea
        self.canvas = FigureCanvasTkAgg(self.fig, master=self)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        toolbar = NavigationToolbar2Tk(self.canvas, self)
        toolbar.update()
        toolbar.pack(side=tk.BOTTOM)
        toolbar.home()

        # toggle refo/tria button
        dep_btn = tk.Button(master=self, text='refo/tria toggle', width=BTN_W, command=self.toggle_dep_type)
        dep_btn.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

        # toggle 2D/3D button
        dim_btn = tk.Button(master=self, text='2D/3D toggle', width=BTN_W, command=self.toggle_dim_type)
        dim_btn.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)

        # default toggle settings
        self.dep_type = False
        self.dim_type = True

    def refresh(self):
        ''' update window '''

        self.ax.clear()
        if self.dim_type:
            if self.dep_type:
                self.ax = self.parent.obj.plt_tria(self.ax)
            else:
                self.ax = self.parent.obj.plt_refo(self.ax)
        else:
            amin = self.parent.obj.dx if self.dep_type else self.parent.obj.a
            self.ax = self.parent.obj.plt_3d(self.ax, amin=amin, dep_type=self.dep_type)
        self.canvas.draw()

    @staticmethod
    def xor(a, b):
        return bool(a) != bool(b)

    def toggle_dep_type(self):
        self.dep_type = self.xor(self.dep_type, 1)
        self.refresh()

    def toggle_dim_type(self):
        self.dim_type = self.xor(self.dim_type, 1)
        self.change_dim_type()
        self.refresh()

    def change_dim_type(self):
        self.fig.delaxes(self.ax)
        if self.dim_type:
            self.fig.set_size_inches(FIG_SIZE, forward=True)
            self.ax = self.fig.gca()
        else:
            self.ax = Axes3D(self.fig)
            self.parent.obj.plt_3d_init(self.fig, self.ax)
class MplCanvas(FigureCanvasQTAgg, customthreads.StoppableThread):

    def __init__(self, xlim=None, ylim=None, channel=1, x_range=None,
                 parent=None, post_process=None, width=5, height=4, dpi=100,
                 *args, **kwargs):

        customthreads.StoppableThread.__init__(self, *args, **kwargs)

        self.lock = Lock()
        self.in_queue = queue.Queue()

        self.xlim = xlim
        self.ylim = ylim
        self.x_range = x_range

        if(self.x_range is None):
            self.x_range = range(self.xlim[0], self.xlim[1])

        self.fig = Figure(figsize=(width, height), dpi=dpi)
        FigureCanvasQTAgg.__init__(self, self.fig)
        FigureCanvasQTAgg.setSizePolicy(self,
                                        QtWidgets.QSizePolicy.Expanding,
                                        QtWidgets.QSizePolicy.Expanding)
        FigureCanvasQTAgg.updateGeometry(self)

        self.axes_list = []
        self.setParent(parent)

        self.set_channel(channel)

        self.post_process = post_process
        if(self.post_process is None):
            self.post_process = lambda data: data

    def set_channel(self, channel):
        self.lock.acquire()

        self.channel = channel

        '''clear subplots'''
        if(self.axes_list is not []):
            for ax in self.axes_list:
                self.fig.delaxes(ax)

        self.axes_list = []
        for i in range(1, self.channel+1):
            self.axes_list.append(self.fig.add_subplot(self.channel, 1, i))
            self.axes_list[i-1].hold(False)

        self.lock.release()

    def run(self):
        print(self.x_range)
        while(self.is_stopped() is False):
            try:
                data = self.in_queue.get_nowait()
                split_data = ast.split_channel(data, self.channel)
                p_split_data = [self.post_process(sd) for sd in split_data]

                self.lock.acquire()
                for i in range(self.channel):
                    self.axes_list[i].plot(self.x_range, p_split_data[i], 'b')
                    self.axes_list[i].set_xlim(self.xlim)
                    self.axes_list[i].set_ylim(self.ylim)
                self.draw()
                self.lock.release()

            except queue.Empty:
                pass
Exemple #38
0
    class TransformEditor(QtGui.QMainWindow):
        """GUI to edit transformations.

        .. warning::

            Note that this module requires PyQt4.

        Parameters
        ----------
        transform_manager : TransformManager
            All nodes that are reachable from the base frame will be editable

        frame : string
            Name of the base frame

        xlim : tuple, optional (-1, 1)
            Lower and upper limit for the x position. Defines the range of the
            plot and the range of the slider.

        ylim : tuple, optional (-1, 1)
            Lower and upper limit for the y position. Defines the range of the
            plot and the range of the slider.

        zlim : tuple, optional (-1, 1)
            Lower and upper limit for the z position. Defines the range of the
            plot and the range of the slider.

        s : float, optional (default: 1)
            Scaling of the axis and angle that will be drawn

        figsize : tuple of integers, optional (default: (10, 10))
            Width, height in inches.

        dpi : integer, optional (default: 100)
            Resolution of the figure.

        parent : QtGui.QWidget, optional (default: None)
            Parent widget.

        Attributes
        ----------
        transform_manager : TransformManager
            Result, all frames are expressed in the base frame
        """
        def __init__(self,
                     transform_manager,
                     base_frame,
                     xlim=(-1.0, 1.0),
                     ylim=(-1.0, 1.0),
                     zlim=(-1.0, 1.0),
                     s=1.0,
                     figsize=(10, 10),
                     dpi=100,
                     window_size=(500, 600),
                     parent=None):
            self.app = QtGui.QApplication(sys.argv)

            super(TransformEditor, self).__init__(parent)
            self.transform_manager = self._init_transform_manager(
                transform_manager, base_frame)
            self.base_frame = base_frame
            self.xlim = xlim
            self.ylim = ylim
            self.zlim = zlim
            self.s = s
            self.figsize = figsize
            self.dpi = dpi
            self.window_size = window_size

            self.setWindowTitle("Transformation Editor")
            self.axis = None

            self._create_main_frame()
            self._on_node_changed([
                node for node in self.transform_manager.nodes
                if node != self.base_frame
            ][0])

        def _init_transform_manager(self, transform_manager, frame):
            """Transform all nodes into the reference frame."""
            tm = TransformManager()
            if frame not in transform_manager.nodes:
                raise KeyError("Unknown frame '%s'" % frame)

            for node in transform_manager.nodes:
                try:
                    node2frame = transform_manager.get_transform(node, frame)
                    tm.add_transform(node, frame, node2frame)
                except KeyError:
                    pass  # Frame is not connected to the reference frame

            return tm

        def _create_main_frame(self):
            """Create main frame and layout."""
            self.main_frame = QtGui.QWidget()

            self.frame_editor = PositionEulerEditor(self.base_frame, self.xlim,
                                                    self.ylim, self.zlim)
            self.connect(self.frame_editor, QtCore.SIGNAL("frameChanged()"),
                         self._on_update)

            frame_selection = self._create_frame_selector()

            plot = self._create_plot()

            vbox = QtGui.QVBoxLayout()
            vbox.addWidget(self.frame_editor)
            vbox.addWidget(frame_selection)
            vbox.addWidget(plot)

            main_layout = QtGui.QHBoxLayout()
            main_layout.addLayout(vbox)

            self.main_frame.setLayout(main_layout)
            self.setCentralWidget(self.main_frame)
            self.setGeometry(0, 0, *self.window_size)

        def _create_frame_selector(self):
            frame_selection = QtGui.QComboBox()
            for node in self.transform_manager.nodes:
                if node != self.base_frame:
                    frame_selection.addItem(node)
            self.connect(frame_selection,
                         QtCore.SIGNAL("activated(const QString&)"),
                         self._on_node_changed)
            return frame_selection

        def _create_plot(self):
            plot = QtGui.QWidget()
            canvas_group = QtGui.QGridLayout()
            self.fig = Figure(self.figsize, dpi=self.dpi)
            self.fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
            self.canvas = FigureCanvas(self.fig)
            self.canvas.setParent(self.main_frame)
            canvas_group.addWidget(self.canvas, 1, 0)
            mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
            canvas_group.addWidget(mpl_toolbar, 2, 0)
            plot.setLayout(canvas_group)
            return plot

        def _on_node_changed(self, node):
            """Slot: manipulatable node changed."""
            self.node = str(node)
            A2B = self.transform_manager.get_transform(self.node,
                                                       self.base_frame)
            self.frame_editor.set_frame(A2B)
            self._plot()

        def _on_update(self):
            """Slot: transformation changed."""
            self.transform_manager.add_transform(self.node, self.base_frame,
                                                 self.frame_editor.A2B)
            self._plot()

        def _plot(self):
            """Draw plot."""
            if self.axis is None:
                elev, azim = 30, 60
            else:
                elev, azim = self.axis.elev, self.axis.azim
                self.fig.delaxes(self.axis)

            self.axis = self.fig.add_subplot(111, projection="3d")
            self.axis.view_init(elev, azim)

            self.axis.set_xlim(self.xlim)
            self.axis.set_ylim(self.ylim)
            self.axis.set_zlim(self.zlim)

            p = self.transform_manager.get_transform(self.node,
                                                     self.base_frame)[:3, 3]
            self.axis.scatter(p[0], p[1], p[2], s=100)
            self.transform_manager.plot_frames_in(self.base_frame,
                                                  ax=self.axis,
                                                  s=self.s)

            self.canvas.draw()

        def show(self):
            """Start GUI."""
            super(TransformEditor, self).show()
            self.app.exec_()
Exemple #39
0
class MatplotlibWidget(FigureCanvas):
    """
    Class handling 1D, 2D, 3D data and displaying them in a canvas as 1D curve
    graphs, 2D images or multiple 2D images.
    """

    MASK_HIDDEN = 0
    MASK_SHOWN = 1
    MASK_ONLY = 2

    def __init__(self, graphMode=None, parent=None, name=None, width=5, height=4,
                 dpi=100, bgColor=None, valueRange=None,
                 maskLabels=None):
        """
        Create matplotlib 'front-end' widget which can render 1D,2D,3D data as
        1D or 2D graphs and handle masks.
        """
        if debug : print '**xndarrayViewRenderer.__init__  ...'
        self.parent = parent

        if graphMode: self.graphMode = graphMode
        else: self.graphMode = viewModes.MODE_2D

        self.fwidth = width
        self.fheight = height
        self.dpi = dpi

        # Will define the range of the colormap associated to values:
        if debug: print 'valueRange :', valueRange
        #valueRange = [0.001, 0.2] #noise var
        #valueRange = [0.001, 0.5] #noise ARp
        #valueRange = [0, 11]
        if valueRange is not None:
            self.norm = Normalize(valueRange[0],
                                  valueRange[1]+_N.abs(valueRange[1])*.01,
                                  clip=True)
            self.backgroundValue = valueRange[0] - 100
        else:
            self.norm = None
            self.backgroundValue = 0 #?
        # Define the range of the colormap associated to the mask:
        # will be used to draw contours of mask
        self.maskCm = None
        self.maskLabels = maskLabels
        if debug: print '######### maskLabels :', maskLabels
        if maskLabels is not None:
            _N.random.seed(1) # ensure we get always the same random colors
            #TODO: put the random seed back in the same state as before!!!
            rndm = _N.random.rand(len(maskLabels),3)
            # black:
            #fixed = _N.zeros((len(maskLabels),3)) + _N.array([0.,0.,0.])
            # green:
            #fixed = _N.zeros((len(maskLabels),3)) + _N.array([0.,1.,0.])
            #white:
            fixed = _N.zeros((len(maskLabels),3)) + _N.array([1.,1.,1.])
            # Create uniform colormaps for every mask label
            # self.maskCm = dict(zip(maskLabels,
            #                       [ListedColormap([ tuple(r) ]) for r in rndm]))
            self.maskCm = dict(zip(maskLabels,
                                   [ListedColormap([tuple(r)]) for r in fixed]))
        self.displayMaskFlag = self.MASK_HIDDEN

        # Set the color of the widget background
        if self.parent:
            bgc = parent.backgroundBrush().color()
            #bgcolor = float(bgc.red())/255.0, float(bgc.green())/255.0, \
            #          float(bgc.blue())/255.0
            bgcolor = "#%02X%02X%02X" % (bgc.red(), bgc.green(), bgc.blue())
        else: bgcolor = 'w'

        # Create the matplotlib figure:
        self.fig = Figure(figsize=(width, height), dpi=dpi,
                          facecolor=bgcolor, edgecolor=bgcolor)
        # Size of the grid of plots:
        self.subplotsH = 0
        self.subplotsW = 0
        self.axes = None
        self.showAxesFlag = True
        self.showAxesLabels = True

        # Init the parent Canvas:
        FigureCanvas.__init__(self, self.fig)

        # Some QT size stuffs
        self.reparent(parent, QPoint(0, 0))
        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        # Color bar related stuffs:
        self.showColorBar = False
        self.colorBars = None
        # color associated to position where mask=0 :
        self.bgColor = 'w'#QColor('white') if bgColor==None else bgColor

        # Default colormap (~rainbow) : black-blue-green-yellow-red
        self.colorMapString = '0;0;0.5;0.0;0.75;1.0;1.;1.0#' \
                              '0;0;0.5;1;0.75;1;1;0.#'       \
                              '0;0;0.25;1;0.5;0;1;0.'
        self.setColorMapFromString(self.colorMapString)
        self.update()

        # Signal stuffs:
        #self.mpl_connect('button_release_event', self.onRelease)
        self.mpl_connect('motion_notify_event', self.onMove)
        self.mpl_connect('button_press_event', self.onClick)

    def setBackgroundColor(self, color):
        if type(color) == QColor:
            self.bgColor = tuple([c/255. for c in color.getRgb()])
        else:
            self.bgColor = color # assume letter code/ hex color string / ...
                                 # anything supported by matplotlib.colors
                                 #TODO maybe do some checks ?
        if debug:print 'setting over/under color ', self.bgColor
        self.colorMap.set_under(color=self.bgColor)
        self.colorMap.set_over(color=self.bgColor)

    def sizeHint(self):
        w = self.fig.get_figwidth()
        h = self.fig.get_figheight()
        return QSize(w, h)

    def getColorMapString(self):
        return self.colorMapString

    def setColorMapFromString(self, scm):

        if debug : print 'MatplotlibWidget.setColorMapFromString'
        scm = str(scm)
        if debug : print ' recieved scm:', scm
        # Make sure we do not have any negative values :
        subResult = re.subn('(\+[0-9]+(\.\d*)?)','0.',scm)
        if debug and subResult[1] > 0:
            print ' !!! found negative values !!!'
            sys.exit(1)
        scm = subResult[0]
        self.colorMapString = scm
        if debug : print ' negative filtered scm :', scm

        self.colorMap = cmstring_to_mpl_cmap(scm)
        # Set colors corresponding to [minval-1 , minval] to background color:
        self.setBackgroundColor(self.bgColor)

    def setGraphMode(self, m):
        if self.graphMode == m:
            return
        if debug: print 'xndarrayViewRenderer.setGraphMode:',m
        self.graphMode = m
        self.computeFigure()

    def minimumSizeHint(self):
        return QSize(100, 100)


    def setMaskDisplay(self, flag):
        if self.displayMaskFlag == flag:
            return
        self.displayMaskFlag = flag
        self.resetGraph()
        self.refreshFigure()

    def toggleColorbar(self):
        if debug: print "MatplotlibWidget toggleColorbar..."
        self.showColorBar = not self.showColorBar
        if debug: print ' showColorBar = %s' %(['On','Off'][self.showColorBar])
        #if not self.showColorBar:
        self.resetGraph()

        #self.resetGraph()
        self.refreshFigure()
        #self.draw()

    def hideAxes(self):
        if not self.showAxesFlag:
            return
        self.showAxesFlag = False
        for ax in self.axes:
            ax.set_axis_off()
        self.adjustSubplots()
        self.draw()

    def showAxes(self):
        if self.showAxesFlag:
            return
        self.showAxesFlag = True
        for ax in self.axes:
            ax.set_axis_on()
        self.adjustSubplots()
        self.draw()

    def toggleAxesLabels(self):
        self.showAxesLabels = not self.showAxesLabels
        for a in self.axes:
            self.plotAxesLabels(a)
        self.adjustSubplots()
        self.draw()

    def setMaskLabel(self, label):
        if debug: print "MatplotlibWidget setMaskLabel ..."
        self.maskLabel = label
        self._applyMask()
        self.resetGraph()
        self.refreshFigure()


    def _applyMask(self):
        if debug: print "MatplotlibWidget applyMask ..."
        self.maskedValues = self.values.copy()
        self.maskedErrors = None if self.errors==None else self.errors.copy()
        if self.mask != None:
            if debug: print 'self.maskLabel:', self.maskLabel
            if self.maskLabel != 0:
                m = (self.mask != self.maskLabel)
            else:
                m = (self.mask == 0)
            #print 'm :', m
            if debug: print 'backgroundValue :', self.backgroundValue
            self.maskedValues[m] = self.backgroundValue
            if self.errors != None:
                self.maskedErrors[m] = 0

    def updateData(self, cub, mask=None, maskLabel=0, maskName='mask',
                   otherSlices=None):
        if debug:
            print "MatplotlibWidget update data ..."
            print "Got cuboid:"
            print cub.descrip()
            if mask is not None:
                print 'Got mask:', mask.shape
                print mask
        # Retrieve data and make everything be 3D-shaped:
        deltaDims = 3-cub.get_ndims()
        targetSh = cub.data.shape + (1,) * deltaDims
        self.domainNames = cub.axes_names + [None] * deltaDims
        self.domainValues = [cub.axes_domains[a] for a in cub.axes_names] + \
            [None] * deltaDims
        self.values = cub.data.reshape(targetSh)
        self.mask = None if mask==None else mask.reshape(targetSh)
        self.maskName = maskName
        #self.errors = None if cub.errors==None else cub.errors.reshape(targetSh)
        self.errors = None
        self.valueLabel = cub.value_label
        self.maskLabel = maskLabel
        self.otherSlices = otherSlices
        self._applyMask()
        if debug:
            print 'MatplotlibWidget.update: got view:'
            print '**Domains:'
            for i in xrange(len(self.domainNames)):
                if self.domainNames[i]!=None:
                    if _N.isreal(self.domainNames[i][0]) :
                        print '%s : [%d %d]' %(self.domainNames[i],
                                               self.domainValues[i].min(),
                                               self.domainValues[i].max())
                    else:
                        print '%s : [%s ... %s]' %(self.domainNames[i],
                                                   self.domainValues[i][0],
                                                   self.domainValues[i][-1])

            if debug:
                print 'self.maskedValues:', self.maskedValues.shape
                print self.maskedValues[:,:,0]
            #print 'self.values :', self.values.shape
            if self.errors != None: print 'self.errors:', self.maskedErrors.shape

        self.emit(PYSIGNAL('valuesChanged'),(self.getShortDataDescription(),))
        self.computeFigure()

    def getShortDataDescription(self):
        if self.mask!=None:
            if self.maskLabel > 0:
                v = self.values[self.mask == self.maskLabel]
            else: v = self.values[self.mask != 0]
        else:
            v = self.maskedValues
        if v.size > 0:
            descr = '%1.3g(%1.3g)[%1.3g,%1.3g]' %(v.mean(),v.std(),
                                                  v.min(),v.max())
        else: descr = ''
        return descr

    def resetGraph(self):
        if debug : print 'MatplotlibWidget.resetGraph ...'

        if self.colorBars != None:
            if debug: print 'self.colorbars :', self.colorBars
            for cb in self.colorBars:
                self.fig.delaxes(cb.ax)
            self.colorBars = None

        if self.graphMode == viewModes.MODE_HIST:
            if self.axes:
                for a in self.axes:
                    self.fig.delaxes(a)

            ax = self.fig.add_subplot(111)
            ax.zValue = 0
            self.axes = [ax]
            #self.axes.clear()
            self.axes[0].hold(False)

        else:
            nbZVal = self.values.shape[2]
            if debug: print 'nbZVal :', nbZVal
            h = round(nbZVal**.5)
            w = _N.ceil(nbZVal/h)
            if 1 or (h != self.subplotsH or w != self.subplotsW):
                if self.axes:
                    for a in self.axes:
                        self.fig.delaxes(a)
                self.subplotsW = w
                self.subplotsH = h
                self.axes = []
                if debug: print 'add subplots : w=%d, h=%d' %(w,h)
                for i in xrange(1,nbZVal+1):
                   #if debug: print ' add(%d, %d, %d)' %(h,w,i)
                   ax = self.fig.add_subplot(h,w,i)
                   ax.zValue = i-1
                   self.axes.append(ax)

        self.adjustSubplots()

    def adjustSubplots(self):
        if debug: print "adjustSubplots ..."
        if self.graphMode == viewModes.MODE_HIST:
            self.fig.subplots_adjust(left=0.2, right=.95,
                                     bottom=0.2, top=.9,
                                     hspace=0., wspace=0.)
            return

        if self.values.shape[2] == 1:
            if not self.showAxesFlag:
                self.fig.subplots_adjust(left=0.2, right=.8,
                                         bottom=0.2, top=.8,
                                         hspace=0.05, wspace=0.05)
            elif not self.showAxesLabels:
                if self.graphMode == viewModes.MODE_2D:
                    self.fig.subplots_adjust(left=0.05, right=.95,
                                             bottom=0.01, top=.95,
                                             hspace=0., wspace=0.)
                else:
                    self.fig.subplots_adjust(left=0.2, right=.95,
                                             bottom=0.1, top=.95,
                                             hspace=0., wspace=0.)

            else:
                self.fig.subplots_adjust(left=0.1, right=.95,
                                         bottom=0.1, top=.9,
                                         hspace=0.05, wspace=0.05)
        else:
            if not self.showAxesFlag:
                self.fig.subplots_adjust(left=0., right=1.,
                                         bottom=0., top=1.,
                                         hspace=0.05, wspace=0.05)
            elif not self.showAxesLabels:
                self.fig.subplots_adjust(left=0.1, right=.9,
                                         bottom=0.2, top=.9,
                                         hspace=0.7, wspace=0.3)
            else:
                self.fig.subplots_adjust(left=0.1, right=.9,
                                         bottom=0.1, top=.9,
                                         hspace=0.01, wspace=0.7)

    def showMask(self, splot, mask):
        if mask != None:
            nr, nc = mask.shape
            extent = [-0.5, nc-0.5, -0.5, nr-0.5]

            if self.displayMaskFlag == self.MASK_SHOWN:
                labels = _N.unique(mask)
                for il, lab in enumerate(labels):
                    if lab != 0:
                        if self.maskCm!=None : cm = self.maskCm[lab]
                        else : cm = get_cmap('binary')
                        splot.contour((mask==lab).astype(int), 1,
                                      cmap=cm, linewidths=2., extent=extent,alpha=.7)
                                     #cmap=cm, linewidths=1.5, extent=extent,alpha=.7)
            if self.displayMaskFlag == self.MASK_ONLY:
                if self.maskLabel == 0:
                    labels = _N.unique(mask)
                    for il, lab in enumerate(labels):
                        if lab != 0:
                            if self.maskCm != None:
                                cm = self.maskCm[lab]
                            else:
                                cm = get_cmap('binary')
                            ml = (mask==lab).astype(int)
                            print 'contouf of mask label %d -> %d pos' \
                                %(lab, ml.sum())
                            splot.contourf(ml, 1,
                                           cmap=cm, linewidths=1., extent=extent)
                elif (mask==self.maskLabel).sum() > 0:
                    if self.maskCm != None:
                        cm = self.maskCm[_N.where(mask==self.maskLabel)[0]]
                    else:
                        cm = get_cmap('binary')
                    ax.contourf((mask==self.maskLabel).astype(int), 1,
                                cmap=cm, linewidths=1.5, extent=extent)

    def plot1D(self):
        if debug: print 'MatplotlibWidget.computeFigure: MODE_1D'
        di2 = 0
        nbins = 100.

        d1 = self.domainValues[1]
        d0 = self.domainValues[0]
        plotPDF = False
        if d0[0] == 'mean' and len(d0)>1 and d0[1] == 'var':
            plotPDF = True
            if (self.values[1,:] < 10.).all():
                xMin = (self.values[0,:] - 6*self.values[1,:]**.5).min()
                xMax = (self.values[0,:] + 6*self.values[1,:]**.5).max()
            else:
                xMin = (self.values[0,:] - 10*self.values[1,:]**.5).min()
                xMax = (self.values[0,:] + 10*self.values[1,:]**.5).max()
            bins = _N.arange(xMin, xMax, (xMax-xMin)/nbins)

        x = d0 if _N.isreal(d0[0]) else _N.arange(len(d0))

        me = self.maskedErrors.max() if self.errors!=None else 0
        yMax = self.maskedValues.max()+me
        yMin = self.maskedValues.min()-me
        if 1 or self.errors !=None :
            dy = (yMax-yMin)*0.05
            dx = (x.max()-x.min())*0.05
        else: dx,dy = 0,0

        for ax in self.axes:
            ax.hold(True)
            #ax.set_axis_off()
            vSlice = self.maskedValues[:,:,di2]
            if self.errors != None:
                errSlice = self.maskedErrors[:,:,di2]
            for di1 in xrange(self.values.shape[1]):
                if plotPDF:
                    plotNormPDF(ax, bins, vSlice[0,di1], vSlice[1,di1])
                else:
                    print 'di1:',di1
                    print 'domainValues:', self.domainValues
                    if self.domainValues[1] is not None:
                        val = str(self.domainNames[1]) + ' = ' + \
                            str(self.domainValues[1][di1])
                    else:
                        val = 'nothing'
                    ax.plot(x, vSlice[:,di1], picker=ValuePicker(val))
                    #ax.plot(vSlice[:,di1], picker=ValuePicker(val))
                    if not _N.isreal(d0[0]):
                        setTickLabels(self.axes[0].xaxis, d0)
                    if self.errors != None and not _N.allclose(errSlice[:,di1],0.) :
                        ax.errorbar(x, vSlice[:,di1], errSlice[:,di1], fmt=None)
            if not plotPDF:
                ax.set_xlim(x.min()-dx, x.max()+dx)
                ax.set_ylim(yMin-dy, yMax+dy)
            elif ax.get_ylim()[1] > 1.0:
                ax.set_ylim(0, 1.)
            if not self.showAxesFlag:
                ax.set_axis_off()

            self.plotAxesLabels(ax)

            #ax.set_title(self.domainNames[2]+' ' \
            #             +str(self.domainValues[2][di2]))
            di2 += 1

    def plotAxesLabels(self, axis):
        if not self.showAxesLabels:
            axis.set_xlabel('')
            axis.set_ylabel('')
            return

        if self.graphMode == viewModes.MODE_1D:
            axis.set_xlabel(self.domainNames[0])
            axis.set_ylabel(self.valueLabel)
        elif self.graphMode == viewModes.MODE_2D:
            axis.set_ylabel(self.domainNames[0])

            if self.domainValues[1] != None:
                axis.set_xlabel(self.domainNames[1])
        else: #MODE_HIST
            axis.set_xlabel(self.valueLabel)
            axis.set_ylabel('density')


    def plot2D(self):
        if debug: print 'MatplotlibWidget.computeFigure: MODE_2D'
        di2 = 0
        self.colorBars = []
        for ax in self.axes:
            ax.hold(True)
            if self.mask != None:
                self.showMask(ax, self.mask[:,:,di2])
            #print 'maskedValues:', self.maskedValues.min(), self.maskedValues.max()
            if not hasattr(ax, 'matshow'): # matplotlib version < 0.9:
                ms = _matshow(ax, self.maskedValues[:,:,di2], cmap=self.colorMap,
                              norm=self.norm)
            else:
                ms = ax.matshow(self.maskedValues[:,:,di2], cmap=self.colorMap,
                                norm=self.norm)

            if self.showColorBar and len(self.axes)<2:
                if debug: print ' plot colorbar ...'
                self.colorBars.append(self.fig.colorbar(ms))

            if not self.showAxesFlag:
                ax.set_axis_off()
            else:
                setTickLabels(ax.yaxis, self.domainValues[0])
                if self.domainValues[1] != None:
                    setTickLabels(ax.xaxis, self.domainValues[1])

                self.plotAxesLabels(ax)

            #ax.set_title(self.domainNames[2]+' ' \
            #             +str(self.domainValues[2][di2]))
            di2 += 1

    def plotHist(self):
        if debug: print 'MatplotlibWidget.computeFigure: MODE_HIST'

        v = self.values
        if 0 and self.mask != None:
            if debug: print 'self.mask:', _N.unique(self.mask)
            if self.maskLabel > 0:
                #if debug: print 'self.values[self.mask == %d] :' %self.maskLabel
                #if debug: print self.values[self.mask == self.maskLabel]
                vs = [self.values[self.mask == self.maskLabel]]
            else:
                #if debug: print 'self.values[self.mask != 0] :'
                #if debug: print self.values[self.mask != 0]
                vs = [self.values[self.mask == ml] for ml in self.maskLabels
                      if ml!=0]

        else:
            vs = [self.values]
        bins = 30
        #bins = _N.arange(0,1.,0.05)
        normed = True
        colors = ['b','r','g']
        n,bins = _N.histogram(self.values, bins=bins, normed=normed)

        for iv, v in enumerate(vs):
            if v.size > 0:
                fColor = colors[iv]
                alpha = 0.5 if iv > 0 else 1.
                self.axes[0].hold(True)
                n,b,p = self.axes[0].hist(v, bins=bins, normed=normed, fc=fColor,
                                          alpha=alpha)
                #if type(bins) == int :
                #    bins = b
            else:
                print "Nothing in histogram"

        self.plotAxesLabels(self.axes[0])

    def computeFigure(self):
        if debug: print 'MatplotlibWidget.computeFigure: ...'

        # Reset subplots adjustment:
        #self.fig.subplots_adjust(left=0.15, right=.9, bottom=0.2, top=.8,
        #                         hspace=0.1, wspace=0.1)
        self.resetGraph()
        self.refreshFigure()

    def refreshFigure(self):
        if debug : print 'MatplotlibWidget.refreshFigure ...'
        if self.graphMode == viewModes.MODE_1D:
            self.plot1D()
        elif self.graphMode == viewModes.MODE_2D:
            self.plot2D()
        elif self.graphMode == viewModes.MODE_HIST:
            self.plotHist()

        if debug: print 'fig:', self.fig.get_figwidth(), self.fig.get_figheight()

        self.draw()

    def save(self, fn):
        if debug : print 'MatplotlibWidget: self.fig.savefig ...'
        self.fig.savefig(fn)


    def printVal(self, v):
        if not _N.isreal(v): # assume string
            return v
        #else assume number
        elif int(v) == v:  #integer
            return '%d' %v
        else: # float
            return '%1.3g' %v

    def onClick(self, event):
        if debug:
            print 'mpl press event !'
        if not event.inaxes:
            return
        i = round(event.ydata)
        j = round(event.xdata)
        if hasattr(event.inaxes, 'zValue'):
            #if self.graphMode == viewModes.MODE_2D:
            k = event.inaxes.zValue
        else:
            k = -1
        if debug:
            print 'click on :', (i,j,k)
            print 'self.values.shape :', self.values.shape
        if self.otherSlices is not None:
            pos = self.otherSlices.copy()
        else:
            pos = {}
        if self.graphMode == viewModes.MODE_2D:
            if i<self.values.shape[0] and j<self.values.shape[1]:
                for n in xrange(3):
                    if debug: print 'self.domainNames[n]:', self.domainNames[n]
                    if self.domainNames[n] != None:
                        dv = self.domainValues[n][[i,j,k][n]]
                        pos[self.domainNames[n]] = dv
                if self.mask is not None:
                    pos[self.maskName] = self.mask[i,j,k]
        pos[self.valueLabel] = self.values[i,j,k]
        if debug:
            print '-> ', pos
            print "emitting positionClicked ..."
        self.emit(PYSIGNAL("positionClicked"), (pos.keys(), pos.values()) )


    def onMove(self, event):
        if event.inaxes and hasattr(event.inaxes, 'zValue'):
            #print 'zVal:', event.inaxes.zValue
            k = event.inaxes.zValue
            i = round(event.ydata)
            j = round(event.xdata)
            #print 'xdata : %f, ydata : %f' %(event.xdata, event.ydata)
            #print 'i:%d, j:%d, k:%d' %(i,j,k)

            if self.graphMode == viewModes.MODE_2D:
                if i >=self.values.shape[0] or j>=self.values.shape[1]:
                    msg = ''
                else:
                    if self.mask==None or (self.mask[i,j,k] != 0 and          \
                                           (self.maskLabel==0 or          \
                                            self.mask[i,j,k]==self.maskLabel)):
                        msg = '%s: %1.3g' %(self.valueLabel, self.values[i,j,k])
                    else:
                        msg = 'background'
                    if self.mask != None:
                        msg += ', %s:%d' %(self.maskName, self.mask[i,j,k])

                if msg != '':
                    for n in xrange(3):
                        if self.domainNames[n] is not None:
                            dv = self.domainValues[n][[i,j,k][n]]
                            msg += ', %s: %s' \
                                   %(self.domainNames[n], self.printVal(dv))
                    if self.errors != None:
                        msg += ', error: %1.3g' %(self.errors[i,j,k])

            elif self.graphMode == viewModes.MODE_1D:
                msg = '%s: %1.3g, %s: %1.3g' %(self.domainNames[0],event.xdata,
                                               self.valueLabel,event.ydata)


            elif self.graphMode == viewModes.MODE_HIST:
                msg = '%s: %1.3g, %s: %1.3g' %(self.valueLabel,event.xdata,
                                               'freq',event.ydata)
        else:
            msg = ''
        self.emit(PYSIGNAL('pointerInfoChanged'), (msg,))


    def onRelease(self, event):
        if debug:print event.name
        if event.inaxes:
            self.matData = _N.random.randn(10,10)
            self.ai.set_data(self.matData)
class DensityPanel(FigureCanvasWxAgg):
    def __init__(self, parent, **kwargs):
        self.figure = Figure()
        FigureCanvasWxAgg.__init__(self, parent, -1, self.figure, **kwargs)
        self.canvas = self.figure.canvas
        self.SetMinSize((100,100))
        self.figure.set_facecolor((1,1,1))
        self.figure.set_edgecolor((1,1,1))
        self.canvas.SetBackgroundColour('white')
        self.subplot = self.figure.add_subplot(111)
        self.gate_helper = GatingHelper(self.subplot, self)

        self.navtoolbar = None
        self.point_list = []
        self.gridsize = 50
        self.cb = None
        self.x_scale = LINEAR_SCALE
        self.y_scale = LINEAR_SCALE
        self.color_scale = None
        self.x_label = ''
        self.y_label = ''
        self.cmap ='jet'
        
        self.canvas.mpl_connect('button_release_event', self.on_release)
    
    def setpointslists(self, points):
        self.subplot.clear()
        self.point_list = points        
        plot_pts = np.array(points).astype(float)
        
        if self.x_scale == LOG_SCALE:
            plot_pts = plot_pts[(plot_pts[:,0]>0)]
        if self.y_scale == LOG_SCALE:
            plot_pts = plot_pts[(plot_pts[:,1]>0)]
        
        hb = self.subplot.hexbin(plot_pts[:, 0], plot_pts[:, 1], 
                                 gridsize=self.gridsize,
                                 xscale=self.x_scale,
                                 yscale=self.y_scale,
                                 bins=self.color_scale,
                                 cmap=matplotlib.cm.get_cmap(self.cmap))
        
        if self.cb:
            # Remove the existing colorbar and reclaim the space so when we add
            # a colorbar to the new hexbin subplot, it doesn't get indented.
            self.figure.delaxes(self.figure.axes[1])
            self.figure.subplots_adjust(right=0.90)
        self.cb = self.figure.colorbar(hb)
        if self.color_scale==LOG_SCALE:
            self.cb.set_label('log10(N)')
        
        self.subplot.set_xlabel(self.x_label)
        self.subplot.set_ylabel(self.y_label)
        
        xmin = np.nanmin(plot_pts[:,0])
        xmax = np.nanmax(plot_pts[:,0])
        ymin = np.nanmin(plot_pts[:,1])
        ymax = np.nanmax(plot_pts[:,1])

        # Pad all sides
        if self.x_scale==LOG_SCALE:
            xmin = xmin/1.5
            xmax = xmax*1.5
        else:
            xmin = xmin-(xmax-xmin)/20.
            xmax = xmax+(xmax-xmin)/20.
            
        if self.y_scale==LOG_SCALE:
            ymin = ymin/1.5
            ymax = ymax*1.5
        else:
            ymin = ymin-(ymax-ymin)/20.
            ymax = ymax+(ymax-ymin)/20.

        self.subplot.axis([xmin, xmax, ymin, ymax])
    
        self.reset_toolbar()
    
    def getpointslists(self):
        return self.point_list
    
    def setgridsize(self, gridsize):
        self.gridsize = gridsize

    def set_x_scale(self, scale):
        self.x_scale = scale
    
    def set_y_scale(self, scale):
        self.y_scale = scale
        
    def set_color_scale(self, scale):
        if scale==LINEAR_SCALE:
            scale = None
        self.color_scale = scale

    def set_x_label(self, label):
        self.x_label = label
    
    def set_y_label(self, label):
        self.y_label = label
        
    def set_colormap(self, cmap):
        self.cmap = cmap
        self.draw()

    def get_toolbar(self):
        if not self.navtoolbar:
            self.navtoolbar = NavigationToolbar(self.canvas)
        return self.navtoolbar

    def reset_toolbar(self):
        # Cheat since there is no way reset
        if self.navtoolbar:
            self.navtoolbar._views.clear()
            self.navtoolbar._positions.clear()
            self.navtoolbar.push_current()
    
    def set_configpanel(self,configpanel):
        '''Allow access of the control panel from the plotting panel'''
        self.configpanel = configpanel
        
    def on_release(self, evt):
        if evt.button == 3: # right click
            self.show_popup_menu((evt.x, self.canvas.GetSize()[1]-evt.y), None)
            
    def show_popup_menu(self, (x,y), data):
        self.popup_menu_filters = {}
        popup = wx.Menu()
        loadimages_table_item = popup.Append(-1, 'Create gated table for CellProfiler LoadImages')
        selected_gate = self.configpanel.gate_choice.get_gatename_or_none()
        selected_gates = []
        if selected_gate:
            selected_gates = [selected_gate]
        self.Bind(wx.EVT_MENU, 
                  lambda(e):ui.prompt_user_to_create_loadimages_table(self, selected_gates), 
                  loadimages_table_item)
        
        show_images_in_gate_item = popup.Append(-1, 'Show images in gate')
        show_images_in_gate_item.Enable(selected_gate is not None)
        self.Bind(wx.EVT_MENU, self.show_images_from_gate, show_images_in_gate_item)
        if p.object_table:
            show_objects_in_gate_item = popup.Append(-1, 'Show %s in gate'%(p.object_name[1]))
            show_objects_in_gate_item.Enable(selected_gate is not None)
            self.Bind(wx.EVT_MENU, self.show_objects_from_gate, show_objects_in_gate_item)

        self.PopupMenu(popup, (x,y))
Exemple #41
0
class frame_plot(frame):
    instancias = []
    instancia_selecionada = None

    # funcões de geters e sets

    def get_lines_axes(self, index):
        if (isinstance(index, int)):
            subplot = self.subplots[0]
        else:
            subplot = index
        return subplot.lines

    def get_lines_lengenda(self, index):
        if (isinstance(index, int)):
            subplot = self.subplots[index]
        else:
            subplot = index

        return subplot.legend().get_lines()

    def get_visible_lines(self, index):
        try:
            array_linhas_visiveis = []
            if (isinstance(index, int)):
                subplot = self.subplots[0]
            else:
                subplot = index
            for linha in subplot.lines:
                if (linha.get_visible()):
                    array_linhas_visiveis.append(linha)
            return array_linhas_visiveis
        except Exception as e:
            print(str(e))

    def get_serie_line2d(self, line2d):
        try:
            linha = []
            for subplot in self.figura.axes:
                for linha_legenda, linha_serie in zip(
                        self.legendas[subplot].get_lines(), subplot.lines):
                    if (line2d == linha_legenda):
                        linha = 'linha legenda', self.processamento.get_time_serie(
                            linha_serie)
                    if (line2d == linha_serie):
                        linha = 'linha grafico', self.processamento.get_time_serie(
                            linha_serie)
            if (len(linha) > 0):
                return linha[1], linha[0]
            else:
                raise ValueError(
                    "Não foi possivel encontra a serie selecionada")
        except ValueError as e:
            print(str(e))
        except Exception as e:
            print(str(e))

    def get_subplot(self, index, copy=False):
        self.subplots = self.figura.axes
        if (copy == False):
            return self.figura.axes[index], len(self.subplots)
        else:
            return self.subplots[:][index], len(self.subplots)

    def get_subplot_line2d(self, line_2d):
        try:
            cont = 0
            for subplot in self.figura.axes:
                for linha in subplot.lines:
                    if (linha == line_2d):
                        return subplot, cont
                cont = cont + 1
        except Exception as e:
            print(str(e))

    def __init__(self, janela, container, botao_aba, **kwargs):
        frame.__init__(self, janela, 'frame_plot', container)
        frame_plot.add_instancia(self)
        self.kwargs = kwargs
        self.processamento = processamento(self)
        self.current_plot = ""
        self.botao_aba = botao_aba

    #raise frame

    def raise_frame(self):
        try:
            self.tkraise()
            frame_plot.set_current_instancia(self)
        except Exception as e:
            print(str(e))

    #funcões de criacao

    def criar_figura(self, valor):
        try:
            self.figura = Figure(figsize=(5, 5), dpi=100)
            self.figura.subplots_adjust(bottom=0.09,
                                        top=0.95,
                                        left=0.05,
                                        right=0.96)
            self.canvas = FigureCanvasTkAgg(figure=self.figura, master=self)
            self.figura.canvas = self.canvas
            self.canvas.draw()
            self.canvas.get_tk_widget().pack(side=tk.RIGHT,
                                             fill=tk.BOTH,
                                             expand=1)
            self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)

            toolbar = NavigationToolbar2Tk(self.canvas, self)
            toolbar.update()

            self.grid(row=0, column=0, sticky=tk.NSEW)
            self.pick_event = self.figura.canvas.mpl_connect(
                'pick_event', self.on_pick)
            self.click_event = self.figura.canvas.mpl_connect(
                'button_press_event', self.on_click)

        except Exception as e:
            print(str(e))

    #funcões subplot

    def add_subplot(self, column=1):
        self.size_subplots = len(self.figura.axes)
        self.figura.add_subplot(self.size_subplots + 1, column,
                                self.size_subplots + 1)
        self.subplots = self.figura.axes

    def excluir_subplot(self, index):
        if (isinstance(index, int)):
            self.figura.delaxes(self.subplots[index])
            self.size_subplots = len(self.figura.axes)
            self.subplots = self.figura.axes
            if (len(self.subplots) > 0):
                self.selecionar_subplot(0)
        else:
            self.figura.delaxes(index)
            self.size_subplots = len(self.figura.axes)
            self.subplots = self.figura.axes
            if (len(self.subplots) > 0):
                self.selecionar_subplot(0)

    def verificar_subplots(self):
        if (len(self.figura.axes) == 0):
            self.legendas = {}
            self.add_subplot(1)
            self.selecionar_subplot(0)

    def selecionar_subplot(self, index):
        try:
            if (isinstance(index, int)):
                self.subplot_selecionado = self.subplots[index]
            else:
                self.subplot_selecionado = index
            for subplot in self.figura.axes:
                if (subplot == self.subplot_selecionado):
                    subplot.set_facecolor(SUBPLOT_SELECT_COLOR)
                else:
                    subplot.set_facecolor(SUBPLOT_NOT_SELECT_COLOR)
        except Exception as e:
            print(str(e))

    # funcões de atualização

    def update_legenda(self, *args, **kwargs):
        try:
            for subplot in self.figura.axes:
                handles, labels = subplot.get_legend_handles_labels()
                self.legendas[subplot] = subplot.legend(handles, labels)
                if (self.legendas[subplot] != None):
                    for linha in self.legendas[subplot].get_lines():
                        linha.set_picker(5)
        except Exception as e:
            print(str(e))

    def update_escala(self, visible_only=True):
        try:
            for subplot in self.figura.axes:
                if (len(self.get_visible_lines(subplot)) > 0):
                    subplot.relim(visible_only=visible_only)
                    subplot.autoscale_view(True, True, True)
                else:
                    subplot.relim(visible_only=visible_only)
                    subplot.autoscale_view(False, False, False)
        except Exception as e:
            print(str(e))

    def update_subplots(self):
        for subplot in self.figura.axes:
            if (len(subplot.lines) == 0 and self.current_plot == "Normal"):
                self.excluir_subplot(subplot)
        quant_subplots = len(self.figura.axes)
        cont_subplot = 1
        for subplot in self.figura.axes:
            subplot.change_geometry(quant_subplots, 1, cont_subplot)
            cont_subplot += 1

    def update_canvas(self, *args, **kwargs):
        self.canvas.draw()

    def update_screen(self):
        try:
            self.update_subplots()
            self.update_escala(self.subplot_selecionado)
            self.update_legenda()
            self.update_canvas()
        except Exception as e:
            print(str(e))

    # funcões de plotagem

    def plot_normal(self,
                    data_x,
                    data_y,
                    x_label,
                    y_label,
                    index_axes=-1,
                    plot_date=True,
                    **kwargs):
        try:
            if (self.current_plot != "Normal"):
                self.figura.clear()
            self.verificar_subplots()
            if (isinstance(index_axes, int)):
                if (index_axes == -1):
                    subplot = self.subplot_selecionado
                elif (index_axes >= 0):
                    subplot = self.figura.axes[index_axes]
            else:
                subplot = index_axes
            if (plot_date):
                subplot.xaxis.set_major_formatter(
                    mdates.DateFormatter('%d/%m/%Y'))
            line_2d, = subplot.plot(data_x, data_y, **kwargs)
            self.subplot_selecionado.set_xlabel(x_label)
            self.subplot_selecionado.set_ylabel(y_label)
            self.current_plot = "Normal"

            line_2d.set_picker(5)
            return line_2d, subplot
        except Exception as e:
            print(str(e))

    def box_plot(self, data, **kwargs):
        try:
            if (self.current_plot != "Boxplot"):
                self.figura.clear()
            self.verificar_subplots()
            self.subplot_selecionado.boxplot(data, **kwargs)
            self.current_plot = "Boxplot"
        except Exception as e:
            print(str(e))

    def plot_bar(self, array_valores, array_text):
        pass

    def plot_scatter(self, data_x, data_y, **kwargs):
        if (self.current_plot != "Scatter"):
            self.figura.clear()
            self.verificar_subplots()
        self.subplot_selecionado.plot(data_x, data_y, 'o', **kwargs)
        self.current_plot = "Scatter"

    def plot_histograma(self,
                        array_valores,
                        quantidade_classes,
                        normed=False,
                        **kwargs):
        try:
            if (self.current_plot != "Histogram"):
                self.figura.clear()
                self.verificar_subplots()
            self.subplot_selecionado.hist(array_valores,
                                          quantidade_classes,
                                          normed=normed,
                                          **kwargs)
            self.update_canvas()
            self.current_plot = "Histogram"
        except Exception as e:
            print(str(e))

    def plot_autocorrelacao(self,
                            data_y,
                            titulo="Autocorrelação",
                            tipo_plot="pacf",
                            lags=None,
                            alpha=0.05,
                            **kwargs):
        if (self.current_plot != "Autocorrelação"):
            self.figura.clear()
            self.verificar_subplots()
        if (tipo_plot == "pacf"):
            sm.graphics.tsa.plot_pacf(data_y,
                                      ax=self.subplot_selecionado,
                                      title=titulo,
                                      lags=lags,
                                      alpha=alpha,
                                      **kwargs)
        elif (tipo_plot == "acf"):
            sm.graphics.tsa.plot_acf(data_y,
                                     ax=self.subplot_selecionado,
                                     title=titulo,
                                     lags=lags,
                                     alpha=alpha,
                                     **kwargs)
        self.current_plot = "Autocorrelação"

    def fill_area(self, data_x, y, z, index_subplot=None, **kwargs):
        if (self.current_plot != "Normal"):
            self.figura.clear()
        if (isinstance(index_subplot, int)):
            if (index_subplot == None):
                subplot = self.subplot_selecionado
            elif (index_subplot >= 0):
                subplot = self.figura.axes[index_subplot]
        else:
            subplot = index_subplot

        figura = subplot.fill_between(data_x, y, z, **kwargs)
        self.current_plot = "Normal"

        return figura, subplot

    #funcões eventos

    def on_motion(self, event):
        try:
            pass
        except Exception as e:
            print(str(e))

    def on_figure_enter(self, event):
        try:
            pass
        except Exception as e:
            print(str(e))

    def on_figure_leave(self, event):
        try:
            pass
        except Exception as e:
            print(str(e))

    def on_axes_enter(self, event):
        try:
            pass
        except Exception as e:
            print(str(e))

    def on_axes_leave(self, event):
        try:
            pass
        except Exception as e:
            print(str(e))

    def on_click(self, event):
        try:
            self.canvas.get_tk_widget().focus_force()
            subplot = event.inaxes
            if (subplot != None and subplot != self.subplot_selecionado
                    and not self.click_pick_event):
                self.selecionar_subplot(subplot)
                self.update_canvas()
            self.click_pick_event = False
        except Exception as e:
            print(str(e))

    def on_pick(self, event):
        try:
            self.click_pick_event = True
            objeto = event.artist
            evento_mouse = event.mouseevent
            key = evento_mouse.key
            serie, tipo_linha = self.get_serie_line2d(objeto)
            if (tipo_linha == 'linha grafico'):
                if (key == None):
                    self.processamento.processamento_plot.selecionar_serie(
                        serie, True, True)
                elif (key == 'alt'):
                    self.processamento.processamento_plot.selecionar_serie(
                        serie, True, False)
            if (tipo_linha == 'linha legenda'):
                if (evento_mouse.button == 1):
                    self.processamento.processamento_plot.selecionar_serie(
                        serie, True, True)
                if (evento_mouse.button == 2):
                    self.processamento.processamento_plot.selecionar_serie(
                        serie, True, True)
                if (evento_mouse.button == 3):
                    dirt = self.janela.get_mouse_position()
                    self.criar_menu_opcoes(serie, dirt["x"], dirt["y"])

        except Exception as e:
            print(str(e))

    def on_key_press(self, event):
        try:
            print(event.key)
        except Exception as e:
            print(str(e))

    def on_key_release(self, event):
        try:
            pass
        except Exception as e:
            print(str(e))

    # função criacão menu opções

    def criar_menu_mover_plot(self, serie, menu_opcoes):
        try:

            def mover_novo_subplot():
                self.add_subplot(1)
                self.selecionar_subplot(-1)
                self.processamento.processamento_plot.move_plot_serie(
                    serie, index_subplot=-1)

            menu_mover_plot = tk.Menu(menu_opcoes, tearoff=0)
            menu_opcoes.add_cascade(label="Mover para", menu=menu_mover_plot)

            cont = 0
            for subplot in self.subplots:
                if (subplot != serie.subplot):
                    menu_mover_plot.add_command(
                        label="Subplot " + str(cont + 1),
                        command=lambda index_subplot=cont: self.processamento.
                        processamento_plot.move_plot_serie(
                            serie, index_subplot=index_subplot))
                cont = cont + 1

            menu_mover_plot.add_command(label="Novo subplot",
                                        command=lambda: mover_novo_subplot())
        except Exception as e:
            print(str(e))

    def criar_menu_opcoes(self, serie, mouse_x, mouse_y):
        try:
            menu_opcoes = tk.Menu(self, tearoff=0)
            menu_opcoes.add_command(
                label="Excluir",
                command=lambda: self.processamento.processamento_plot.
                excluir_plot_serie(serie, True))
            menu_opcoes.add_command(
                label="Esconder/Mostrar",
                command=lambda: self.processamento.processamento_plot.
                mudar_visibilidade_plot_serie(serie, True))
            self.criar_menu_mover_plot(serie, menu_opcoes)
            menu_opcoes.post(mouse_x, mouse_y)
        except Exception as e:
            print(str(e))

    # metodos classe
    @classmethod
    def add_instancia(cls, instancia):
        cls.instancias.append(instancia)

    @classmethod
    def remove_instancia(cls, instancia):
        cls.instancias.remove(instancia)

    @classmethod
    def get_instances(cls):
        return cls.instancias

    @classmethod
    def get_current_instacia(cls):
        return cls.instancia_selecionada

    @classmethod
    def set_current_instancia(cls, instancia):
        cls.current_instancia = instancia
Exemple #42
0
class Qt4Mpl2DCanvas(FigureCanvas):
    """  A customized Qt widget for matplotlib figure.
    It can be used to replace GraphicsView of QtGui
    """
    def __init__(self, parent):
        """  Initialization
        """
        # Instantiating matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')

        # initialization
        super(Qt4Mpl2DCanvas, self).__init__(self.fig)

        # set up axis/subplot (111) only for 2D
        self.axes = self.fig.add_subplot(
            111, polar=False)  # return: matplotlib.axes.AxesSubplot

        # plot management
        self._scatterPlot = None
        self._imagePlot = None

        # Initialize parent class and set parent
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        # Variables to manage all lines/subplot
        self._lineDict = {}
        self._lineIndex = 0

        # legend and color bar
        self._colorBar = None
        self._isLegendOn = False
        self._legendFontSize = 8

        return

    def update_image(self, array2d):
        """

        @return:
        """

        self._imagePlot.set_data(array2d)

        self._flush()

        return

    def has_plot(self, plot_type):
        if plot_type == 'image' and self._imagePlot is not None:
            return True

        return False

    @property
    def is_legend_on(self):
        """
        check whether the legend is shown or hide
        Returns:
        boolean
        """
        return self._isLegendOn

    def add_arrow(self, start_x, start_y, stop_x, stop_y):
        """
        Example: (0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k')
        @param start_x:
        @param start_y:
        @param stop_x:
        @param stop_y:
        @return:
        """
        head_width = 0.05
        head_length = 0.1
        fc = 'k'
        ec = 'k'

        arrow = self.axes.arrrow(start_x, start_y, stop_x, stop_y, head_width,
                                 head_length, fc, ec)

        return arrow

    def add_contour_plot(self, vec_x, vec_y, matrix_z):
        """ add a contour plot
        Example: reduced data: vec_x: d-values, vec_y: run numbers, matrix_z, matrix for intensities
        :param vec_x: a list of a vector for X axis
        :param vec_y: a list of a vector for Y axis
        :param matrix_z:
        :return:
        """
        # check input
        # TODO - labor
        assert isinstance(vec_x, list) or isinstance(vec_x,
                                                     np.ndarray), 'blabla'
        assert isinstance(vec_y, list) or isinstance(vec_y,
                                                     np.ndarray), 'blabla'
        assert isinstance(matrix_z, np.ndarray), 'blabla'

        # create mesh grid
        grid_x, grid_y = np.meshgrid(vec_x, vec_y)
        #
        # print '[DB...BAT] Grid X and Grid Y size: ', grid_x.shape, grid_y.shape

        # check size
        assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \
                                               '' % (len(vec_x), len(vec_y), matrix_z.shape)

        # # Release the current image
        # self.axes.hold(False)

        # Do plot: resolution on Z axis (color bar is set to 100)
        self.axes.clear()
        contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100)

        labels = [item.get_text() for item in self.axes.get_yticklabels()]

        # Set the Y-axis ticks
        # TODO/ISSUE/NOW: how to make this part more flexible
        if len(labels) == 2 * len(vec_y) - 1:
            new_labels = [''] * len(labels)
            for i in range(len(vec_y)):
                new_labels[i * 2] = '%d' % int(vec_y[i])
            self.axes.set_yticklabels(new_labels)
        # END-IF

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            contour_plot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(contour_plot)
        else:
            self._colorBar.update_bruteforce(contour_plot)

        # Flush...
        self._flush()

    def add_image_plot(self,
                       array2d,
                       xmin,
                       xmax,
                       ymin,
                       ymax,
                       yticklabels=None):
        """

        @param array2d:
        @param xmin:
        @param xmax:
        @param ymin:
        @param ymax:
        @param holdprev:
        @param yticklabels: list of string for y ticks
        @return:
        """
        # check
        assert isinstance(array2d, np.ndarray), 'blabla'
        assert len(array2d.shape) == 2, 'blabla'

        # show image
        self._imagePlot = self.axes.imshow(array2d,
                                           extent=[xmin, xmax, ymin, ymax],
                                           interpolation='none')

        print(self._imagePlot, type(self._imagePlot))

        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            print("[FIXME]: The way to set up the Y-axis ticks is wrong!")
            self.axes.set_yticklabels(yticklabels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # set up color bar
        # # Set color bar.  plt.colorbar() does not work!
        # if self._colorBar is None:
        #     # set color map type
        #     imgplot.set_cmap('spectral')
        #     self._colorBar = self.fig.colorbar(imgplot)
        # else:
        #     self._colorBar.update_bruteforce(imgplot)

        # Flush...
        self._flush()

        return

    def add_image_file(self, imagefilename):
        """Add an image by file
        """
        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img,
                                   extent=[0, 1000, 800, 0],
                                   interpolation='none',
                                   origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        self._flush()

        return

    def add_scatter_plot(self, array2d):
        """
        add scatter plot
        @param array2d:
        @return:
        """
        # check!
        # TODO - 20180801 - Make it work
        assert isinstance(array2d, np.ndarray), 'blabla'
        if array2d.shape[1] < 3:
            raise RuntimeError('blabla3')

        if False:
            array2d = np.ndarray(shape=(100, 3), dtype='float')
            array2d[0][0] = 0
            array2d[0][1] = 0
            array2d[0][2] = 1

            import random
            for index in range(1, 98):
                x = random.randint(1, 255)
                y = random.randint(1, 255)
                z = random.randint(1, 20000)
                array2d[index][0] = float(x)
                array2d[index][1] = float(y)
                array2d[index][2] = float(z)

            array2d[99][0] = 255
            array2d[99][1] = 255
            array2d[99][2] = 1

        self._scatterPlot = self.axes.scatter(array2d[:, 0],
                                              array2d[:, 1],
                                              s=80,
                                              c=array2d[:, 2],
                                              marker='s')

        return

    def clear_canvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        # self.axes.hold(False)

        # clear image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self._colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)
            self.fig.subplots_adjust(bottom=0.15)

        # flush/commit
        self._flush()

        return

    def decrease_legend_font_size(self):
        """
        reset the legend with the new font size
        Returns:

        """
        # minimum legend font size is 2! return if it already uses the smallest font size.
        if self._legendFontSize <= 2:
            return

        self._legendFontSize -= 1
        self._setup_legend(font_size=self._legendFontSize)

        self.draw()

        return

    def getLastPlotIndexKey(self):
        """ Get the index/key of the last added line
        """
        return self._lineIndex - 1

    def getPlot(self):
        """ reture figure's axes to expose the matplotlib figure to PyQt client
        """
        return self.axes

    def getXLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_xlim()

    def getYLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_ylim()

    def hide_legend(self):
        """
        hide the legend if it is not None
        Returns:

        """
        if self.axes.legend() is not None:
            # set visible to be False and re-draw
            self.axes.legend().set_visible(False)
            self.draw()

        self._isLegendOn = False

        return

    def increase_legend_font_size(self):
        """
        reset the legend with the new font size
        Returns:

        """
        self._legendFontSize += 1

        self._setup_legend(font_size=self._legendFontSize)

        self.draw()

        return

    def setXYLimit(self, xmin, xmax, ymin, ymax):
        """
        """
        # for X
        xlims = self.axes.get_xlim()
        xlims = list(xlims)
        if xmin is not None:
            xlims[0] = xmin
        if xmax is not None:
            xlims[1] = xmax
        self.axes.set_xlim(xlims)

        # for Y
        ylims = self.axes.get_ylim()
        ylims = list(ylims)
        if ymin is not None:
            ylims[0] = ymin
        if ymax is not None:
            ylims[1] = ymax
        self.axes.set_ylim(ylims)

        # try draw
        self.draw()

        return

    def set_title(self, title, color):
        """
        set the tile to an axis
        :param title:
        :param color
        :return:
        """
        # check input
        assert isinstance(title,
                          str), 'Title must be a string but not a {0}.'.format(
                              type(title))
        assert isinstance(color,
                          str), 'Color must be a string but not a {0}.'.format(
                              type(color))

        self.setWindowTitle(title)

        self.draw()

        return

    def show_legend(self):
        """
        show the legend if the legend is not None
        Returns:

        """
        if self.axes.legend() is not None:
            # set visible to be True and re-draw
            # self.axes.legend().set_visible(True)
            self._setup_legend(font_size=self._legendFontSize)
            self.draw()

            # set flag on
            self._isLegendOn = True

        return

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w + 1, h)
        self.resize(w, h)

        return

    def _setup_legend(self, location='best', font_size=10):
        """
        Set up legend
        self.axes.legend(): Handler is a Line2D object. Lable maps to the line object
        Args:
            location:
            font_size:

        Returns:

        """
        allowed_location_list = [
            "best", "upper right", "upper left", "lower left", "lower right",
            "right", "center left", "center right", "lower center",
            "upper center", "center"
        ]

        # Check legend location valid or not
        if location not in allowed_location_list:
            location = 'best'

        handles, labels = self.axes.get_legend_handles_labels()
        self.axes.legend(handles, labels, loc=location, fontsize=font_size)

        self._isLegendOn = True

        return
class ProjectAnalysisPage:

    def __init__(self, proj_info):
        self.project = proj_info
        self.project_name = None  # StringVar()
        self.sample_file = None
        self.sample_file_name = None
        self.sample_analysis_file = None
        self.f1 = None
        self.a1 = None
        self.canvas1 = None
        self.f2 = None
        self.a2 = None
        self.canvas2 = None
        self.f3 = None
        self.a3 = None
        self.canvas3 = None

    def create_gui(self, master):
        analysisFrame = Frame(master)
        analysisFrame.pack(fill="both")

        self.sample_file_subframe(analysisFrame)
        self.analysis_plots_subframe(analysisFrame)

        return analysisFrame

    def get_sample_file(self):
        dir_path = filedialog.askopenfilename(title="Select Sample File")

        if dir_path:
            self.sample_file.set(dir_path)
            print("filename: ", os.path.split(dir_path)[-1])
            self.sample_file_name.set(os.path.split(dir_path)[-1])

        proj_name = self.sample_file_name.get()[:-4]
        self.sample_analysis_file.set("".join(os.path.split(dir_path)[:-1]) + "/" + proj_name + ".sa")
        print("sample_analysis_file: ", self.sample_analysis_file.get())

    def sample_file_subframe(self, master):
        self.sample_file = StringVar()
        self.sample_file_name = StringVar()
        self.sample_analysis_file = StringVar()

        self.sample_file.set(self.project.sample_dir.get())

        file_frame = LabelFrame(master, text="Sample File")
        file_frame.pack(fill="both", padx=10)
        # file_frame.grid(row=0, column=0)

        dialog_frame = Frame(master)
        dialog_frame.pack(fill='both', side='top')

        file_name_frame = Frame(master)
        file_name_frame.pack(side='top')


        sample_file_label = Label(dialog_frame, text="Choose sample file: ")
        sample_file_label.pack(anchor='w', side='left', padx=5, pady=5)
        sample_file_entry = Entry(dialog_frame, textvariable=self.sample_file)
        sample_file_entry.pack(anchor='e', expand=1, fill='x', side='left')
        button1 = Button(dialog_frame, text="...", command=self.get_sample_file)
        button1.pack(anchor='e', side='left', padx=10, pady=5)

        file_name_label = Label(file_name_frame, text="Sample file name: ")
        file_name_label.pack( side='left', padx=15, pady=15)
        file_name = Label(file_name_frame, textvariable=self.sample_file_name)
        file_name.pack( side='left', padx=15, pady=15)

    def analysis_plots_subframe(self, master):
        plotter_frame = LabelFrame(master, text="Analysis Plots")
        plotter_frame.pack(fill="both")

        button1 = Button(plotter_frame, text="Print Plot", command=self.print_plots)
        button1.pack(anchor='n', side='top', padx=10, pady=5)

        plots_frame = Frame(plotter_frame)
        plots_frame.pack(fill="both", expand=True)


        plot1_frame = Frame(plots_frame)
        # plot1_frame.pack(fill="both", expand=True, anchor='e', side='top')
        plot1_frame.grid(row=0, column=0, sticky="nw")

        plot2_frame = Frame(plots_frame)
        plot2_frame.grid(row=0, column=1, sticky="ne")
        # plot2_frame.pack(fill="both", expand=True, anchor='w', side='top')


        # initialize plot1
        self.f1 = Figure(figsize=(4, 4), dpi=100)
        self.a1 = self.f1.add_subplot(111)
        self.a1.plot([1, 2, 3, 4, 5, 6, 7, 8], [5, 6, 1, 3, 8, 9, 3, 5], 'g')

        self.canvas1 = FigureCanvasTkAgg(self.f1, plot1_frame)
        tkagg.NavigationToolbar2TkAgg(self.canvas1, plot1_frame)
        self.canvas1.show()
        self.canvas1.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)

        # initialize plot2
        self.f2 = Figure(figsize=(4, 4), dpi=100)
        self.a2 = self.f2.add_subplot(111)
        self.a2.plot([1, 2, 4, 5, 8, 6, 7, 8], [5, 6, 1, 3, 8, 9, 3, 5], 'b')

        self.canvas2 = FigureCanvasTkAgg(self.f2, plot2_frame)
        tkagg.NavigationToolbar2TkAgg(self.canvas2, plot2_frame)
        self.canvas2.show()
        self.canvas2.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)


    def print_plots(self):
        print("yess")
        p = SampleParser()

        print("sample_file.get(): ", self.sample_file.get())
        sample_file = self.sample_file.get()
        analysis_file = self.sample_analysis_file.get()
        print("analysis file: ", analysis_file)
        plot_list = p.parse_sample_file(sample_file, analysis_file)

        print("plot_list: ", plot_list)
        print("lkjsadflkj")

        if len(plot_list[0]) > 0 :
            self.f1.delaxes(self.a1)
            self.a1 = self.f1.gca(projection='3d')
            self.a1.plot_trisurf(plot_list[0], plot_list[1], plot_list[2], cmap='viridis', edgecolor='none')

            self.canvas1.show()
            self.canvas1.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)

            self.f2.delaxes(self.a2)
            self.a2 = self.f2.gca(projection='3d')
            self.a2.plot_trisurf(plot_list[0], plot_list[1], plot_list[3], cmap='viridis', edgecolor='none')

            self.canvas2.show()
            self.canvas2.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)
Exemple #44
0
class PlotFrame(wx.Frame):
    help_msg="""  Menus for
     Import...import project settings file
     Export...export figure (png, jpg) to file
     Print Setup...setup size of figure for printing
     Print Preview...preview printer page
     Print...send figure to a system printer
     Exit...end application

     Basic-2D...View basic 2D representation of data
     Advanced-2D...View 2D representation (with span selection control)
     Advanced-3D...View 3D representation of data

     View-Grid...Toggle grid
     View-Legend...Toggle legend
     View-Fill...Toggle fill representation of data (only for 2D)

     where 'figure' means an image of the matplotlib canvas

     In addition, "Ctrl-C" is bound to copy-figure-to-clipboard    
    """

    about_msg="""
        Option_price_visualisation v0.1  29-Aug-2013

        Nathan Floor, [email protected]
    """

    def __init__(self):
        wx.Frame.__init__(self, None, -1, "Visualise Option Prices and Greeks", size=(300, 500))
        self.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent)

        # intialise variables when start program
        self.viewLegend = False
        self.viewGrid = True
        self.viewFill = False
        
        self.reInitialiseData()
        
        # build interface
        self.Build_Menus()
        self.Build_Panel()
        self.statusbar = self.CreateStatusBar()
        self.Plot_Data()
        self.SetSize(size=(900, 550))

    def reInitialiseData(self):
        self.fileReader = csvReader.Reader()
        self.current_view = 0
        self.time = numpy.arange(0, 31, 1)
        self.indmin = 0
        self.indmax = 31
        self.strike_price = 0

        # initialise data arrays
        self.option_price = []
        self.stock_price = []
        self.delta = []
        self.gamma = []
        self.vega = []
        self.theta = []
        self.rho = []
        self.risidual = []
        
        # initialise secondary data sets
        self.option_price_fill = []
        self.time_span_fill = []
        self.delta_fill = []
        self.gamma_fill = []
        self.vega_fill = []
        self.theta_fill = []
        self.rho_fill = []
        
        # initialise bump values
        self.stock_bump = 0
        self.time_bump = 0
        self.rate_bump = 0
        self.volitile_bump = 0

    # on span-selection of graph
    def onselect(self, xmin, xmax):
        # initialise data sets
        option_price = []
        delta = []
        gamma = []
        theta = []
        rho = []
        vega = []
        maxYLimlist = []
        minYLimlist = []

        # identify the indices of new data set based on selection
        self.indmin = int(xmin)
        #self.indmax = numpy.searchsorted(t, (xmin, xmax))
        self.indmax = min(len(self.time)-1, int(xmax)+1)

        self.time_span_fill = self.time[self.indmin:self.indmax]
        if len(self.option_price) > 0:
            option_price = numpy.array(map(float, self.option_price[self.stock_bump]))
            self.option_price_fill = option_price[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.option_price_fill))
            minYLimlist.append(min(self.option_price_fill))
            if not self.viewFill:
                self.line1.set_data(self.time_span_fill, self.option_price_fill)
        if len(self.delta) > 0:
            delta = numpy.array(map(float, self.delta[self.stock_bump]))
            self.delta_fill = delta[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.delta_fill))
            minYLimlist.append(min(self.delta_fill))
            if not self.viewFill:
                self.line2.set_data(self.time_span_fill, self.delta_fill)
        if len(self.gamma) > 0:
            gamma = numpy.array(map(float, self.gamma[self.stock_bump]))
            self.gamma_fill = gamma[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.gamma_fill))
            minYLimlist.append(min(self.gamma_fill))
            if not self.viewFill:
                self.line3.set_data(self.time_span_fill, self.gamma_fill)
        if len(self.theta) > 0:
            theta = numpy.array(map(float, self.theta[self.time_bump]))
            self.theta_fill = theta[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.theta_fill))
            minYLimlist.append(min(self.theta_fill))
            if not self.viewFill:
                self.line4.set_data(self.time_span_fill, self.theta_fill)
        if len(self.rho) > 0:
            rho = numpy.array(map(float, self.rho[self.rate_bump]))
            self.rho_fill = rho[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.rho_fill))
            minYLimlist.append(min(self.rho_fill))
            if not self.viewFill:
                self.line5.set_data(self.time_span_fill, self.rho_fill)
        if len(self.vega) > 0:
            vega = numpy.array(map(float, self.vega[self.volitile_bump]))
            self.vega_fill = vega[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.vega_fill))
            minYLimlist.append(min(self.vega_fill))
            if not self.viewFill:
                self.line6.set_data(self.time_span_fill, self.vega_fill)
        if len(self.risidual) > 0:
            risidual = numpy.array(map(float, self.risidual[self.stock_bump]))
            self.risidual_fill = risidual[self.indmin:self.indmax]
            #  append to lists for axes limits
            maxYLimlist.append(max(self.risidual_fill))
            minYLimlist.append(min(self.risidual_fill))
            if not self.viewFill:
                self.line7.set_data(self.time_span_fill, self.risidual_fill)

        if len(maxYLimlist) > 0:
            maxYLim = max(maxYLimlist)
        else:
            maxYLim = 1
        if len(minYLimlist) > 0:
            minYLim = min(minYLimlist)
        else:
            minYLim = 0

        self.axes2.set_xlim(self.time_span_fill[0]-1, self.time_span_fill[-1]+1)
        self.axes2.set_ylim(minYLim, maxYLim)
        if not self.viewFill:
            self.canvas.draw()
        else:
            self.Plot_Data()

    def Build_Panel(self):
        self.panel = wx.Panel(self)

        # Create Figure and canvas objects
        self.fig = Figure((6.0, 4.0))
        self.canvas = FigCanvas(self.panel, -1, self.fig)
        self.axes = self.fig.add_subplot(111)

        # setup slider-widgets for controlling GUI
        self.sliderPanel = wx.Panel(self.panel)
        self.stockSlider_label = wx.StaticText(self.sliderPanel, -1, "Stock Price: ")
        self.stockSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, 
            pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
        # self.stockSlider.SetTickFreq(9, 1)
        self.rateSlider_label = wx.StaticText(self.sliderPanel, -1, "Interest Rate: ")
        self.rateSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, 
            pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
        self.rateSlider.SetTickFreq(1, 1)
        self.timeStepSlider_label = wx.StaticText(self.sliderPanel, -1, "Time Step: ")
        self.timeStepSlider = wx.Slider(self.sliderPanel, value=5, minValue=1, maxValue=9, 
            pos=(20, 20), size=(100,-1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
        self.timeStepSlider.SetTickFreq(1, 1)

        self.Bind(wx.EVT_SLIDER, self.onStockSlider, self.stockSlider)
        self.Bind(wx.EVT_SLIDER, self.onRateSlider, self.rateSlider)
        self.Bind(wx.EVT_SLIDER, self.ontimeStepSlider, self.timeStepSlider)        

        # setup options-widgets for controlling graphs
        self.callRadio = wx.RadioButton(self.panel, label="Call options", pos=(10, 10))
        self.putRadio = wx.RadioButton(self.panel, label="Put options", pos=(10, 30))
        self.callRadio.SetValue(True)        
        self.spaceKeeper = wx.StaticText(self.panel, -1, '')
        self.optionPriceCheck = wx.CheckBox(self.panel, label="view Option Price", pos=(20, 20))
        self.deltaCheck = wx.CheckBox(self.panel, label="show Delta", pos=(20, 20))
        self.gammaCheck = wx.CheckBox(self.panel, label="show Gamma", pos=(20, 20))
        self.rhoCheck = wx.CheckBox(self.panel, label="show Rho", pos=(20, 20))
        self.thetaCheck = wx.CheckBox(self.panel, label="show Theta", pos=(20, 20))
        self.fillCheck = wx.CheckBox(self.panel, label="show fill feature", pos=(20, 20))
        self.risidualCheck = wx.CheckBox(self.panel, label="Show Residual", pos=(20, 20))
        self.differenceCheck = wx.CheckBox(self.panel, label="Show Difference", pos=(20, 20))
        self.effectCheck = wx.CheckBox(self.panel, label="Show Greek's effect on option price", pos=(20, 20))
        self.effectCheck.SetValue(True)

        self.Bind(wx.EVT_RADIOBUTTON, self.onCallRadio, self.callRadio)
        self.Bind(wx.EVT_RADIOBUTTON, self.onPutRadio, self.putRadio)
        self.Bind(wx.EVT_CHECKBOX, self.onOptionPrice, self.optionPriceCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onDelta, self.deltaCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onGamma, self.gammaCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onRho, self.rhoCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onTheta, self.thetaCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onRisidual, self.risidualCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onDifferenceCheck, self.differenceCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onShowEffects, self.effectCheck)
        self.Bind(wx.EVT_CHECKBOX, self.onShowFillEffect, self.fillCheck)

        # Create the navigation toolbar, tied to the canvas
        self.toolbar = NavigationToolbar(self.canvas)

        ####################
        # Layout with sizers
        ####################
        flags = wx.ALIGN_LEFT | wx.ALL | wx.ALIGN_CENTER_VERTICAL
        self.sizer = wx.BoxSizer(wx.VERTICAL)

        self.hboxMainBlock = wx.BoxSizer(wx.HORIZONTAL)
        self.vboxOptions = wx.BoxSizer(wx.VERTICAL)
        self.hboxSliders = wx.BoxSizer(wx.HORIZONTAL)
        self.flexiGridSizer = wx.FlexGridSizer(4, 2, 3, 10)

        # adds border around sliders to group related widgets
        self.vboxOptions.AddSpacer(10)
        self.sliderStaticBox = wx.StaticBox(self.sliderPanel, -1, 'Bump Sliders')
        self.sliderBorder = wx.StaticBoxSizer(self.sliderStaticBox, orient=wx.VERTICAL)
        self.flexiGridSizer.AddMany([(self.stockSlider_label), (self.stockSlider, 1, wx.ALL), 
            (self.rateSlider_label), (self.rateSlider, 1, wx.EXPAND), (self.timeStepSlider_label), (self.timeStepSlider, 1, wx.EXPAND)])
        self.sliderBorder.Add(self.flexiGridSizer, 1, wx.ALL, 5)
        self.sliderPanel.SetSizer(self.sliderBorder)
        self.vboxOptions.Add(self.sliderPanel, 0, flag=wx.ALIGN_LEFT|wx.ALL)

        # add border for type of option price
        self.optionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Option Price Type'), orient=wx.VERTICAL)
        self.flexiOptions = wx.FlexGridSizer(3, 1, 3, 10)
        self.flexiOptions.AddMany([(self.callRadio, 1, wx.EXPAND), 
            (self.putRadio, 1, wx.EXPAND), (self.optionPriceCheck, 1, wx.EXPAND)])            
        self.optionsBorder.Add(self.flexiOptions, 1, wx.ALL, 5)
        self.vboxOptions.Add(self.optionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW)
        
        # add border for greeks
        self.greekOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Greek effect Options'), orient=wx.VERTICAL)
        self.flexiOptions2 = wx.FlexGridSizer(6, 1, 3, 10)
        self.flexiOptions2.AddMany([(self.deltaCheck, 1, wx.EXPAND), (self.gammaCheck, 1, wx.EXPAND), 
            (self.rhoCheck, 1, wx.EXPAND), (self.thetaCheck, 1, wx.EXPAND), (self.risidualCheck, 1, wx.EXPAND)])
        self.greekOptionsBorder.Add(self.flexiOptions2, 1, wx.ALL, 5)
        self.vboxOptions.Add(self.greekOptionsBorder, 1, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW)
        #self.vboxOptions.AddSpacer(5)
        
        # add border for other checkable options
        self.otherOptionsBorder = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, 'Extra Options'), orient=wx.VERTICAL)
        self.flexiOptions3 = wx.FlexGridSizer(3, 1, 3, 10)
        self.flexiOptions3.AddMany([(self.fillCheck, 1, wx.EXPAND), (self.differenceCheck, 1, wx.EXPAND), 
            (self.effectCheck, 1, wx.EXPAND)])
        self.otherOptionsBorder.Add(self.flexiOptions3, 1, wx.ALL, 5)
        self.vboxOptions.Add(self.otherOptionsBorder, 0, flag=wx.ALIGN_LEFT|wx.ALL|wx.GROW)
        self.vboxOptions.AddSpacer(5)

        self.hboxMainBlock.Add(self.vboxOptions, 0, flag=flags)
        self.hboxMainBlock.Add(self.canvas, 1, flag=wx.ALIGN_RIGHT|wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
        self.sizer.Add(self.hboxMainBlock, 1, wx.ALL|wx.EXPAND)

        self.sizer.Add(self.toolbar, 0, wx.ALL|wx.ALIGN_RIGHT)
        self.sizer.AddSpacer(1)

        self.canvas.Bind(wx.EVT_KEY_DOWN, self.onKeyEvent)
        self.Bind(wx.EVT_CLOSE, self.onExit)

        self.panel.SetSizer(self.sizer)
        self.sizer.Fit(self)
        self.Center()

    def Build_Menus(self):
        """ build menus """
        MENU_EXIT = wx.NewId()
        MENU_OPEN = wx.NewId()
        MENU_SAVE = wx.NewId()
        MENU_PRINT = wx.NewId()
        MENU_PSETUP = wx.NewId()
        MENU_PREVIEW =wx.NewId()
        MENU_CLIPB =wx.NewId()
        MENU_VIEW_GRID = wx.NewId()
        MENU_HELP =wx.NewId()
        MENU_BASIC = wx.NewId()
        MENU_ADVANCE = wx.NewId()
        MENU_LEGEND = wx.NewId()
        MENU_3D = wx.NewId()
        MENU_ABOUT = wx.NewId()

        menuBar = wx.MenuBar()

        f0 = wx.Menu()
        importItem = wx.MenuItem(f0, MENU_OPEN, "&Import\tCtrl+I")
        f0.AppendItem(importItem)  
        f0.Append(MENU_SAVE,   "&Export",   "Save Image of Plot")
        f0.AppendSeparator()
        printMenu = wx.Menu()
        printMenu.Append(MENU_PSETUP, "Page Setup...",    "Printer Setup")
        printMenu.Append(MENU_PREVIEW,"Print Preview...", "Print Preview")
        printItem = wx.MenuItem(printMenu, MENU_PRINT,  "Print\tCtrl+P")
        printMenu.AppendItem(printItem)
        f0.AppendMenu(-1, '&Print', printMenu)
        f0.AppendSeparator()
        exitItem = wx.MenuItem(f0, MENU_EXIT, 'E&xit\tCtrl+Q')
        f0.AppendItem(exitItem)
        menuBar.Append(f0,     "&File")

        f1 = wx.Menu()
        f1.Append(MENU_BASIC, '&Basic', "Basic View(2D)")
        f1.Append(MENU_ADVANCE, '&Advanced-2D', "Advanced View(2D)")
        f1.Append(MENU_3D, 'A&dvanced-3D', "Advanced View(3D)")

        optionsMenu = wx.Menu()
        viewGridItem = wx.MenuItem(optionsMenu, MENU_VIEW_GRID, 'View &Grid\tCtrl+G')
        optionsMenu.AppendItem(viewGridItem)
        viewLegendItem = wx.MenuItem(optionsMenu, MENU_LEGEND, 'View &Legend\tCtrl+L')
        optionsMenu.AppendItem(viewLegendItem)
        f1.AppendMenu(-1, "&Options", optionsMenu)

        menuBar.Append(f1, "&View")

        f2 = wx.Menu()
        f2.Append(MENU_HELP, "Quick &Reference",  "Quick Reference")
        f2.Append(MENU_ABOUT, "&About",  "About this interface")
        menuBar.Append(f2, "&Help")

        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.onImport,       id=MENU_OPEN)
        self.Bind(wx.EVT_MENU, self.onPrint,        id=MENU_PRINT)
        self.Bind(wx.EVT_MENU, self.onPrinterSetup, id=MENU_PSETUP)
        self.Bind(wx.EVT_MENU, self.onPrinterPreview, id=MENU_PREVIEW)
        self.Bind(wx.EVT_MENU, self.onClipboard,    id=MENU_CLIPB)
        self.Bind(wx.EVT_MENU, self.onExport,       id=MENU_SAVE)
        self.Bind(wx.EVT_MENU, self.onExit ,        id=MENU_EXIT)
        self.Bind(wx.EVT_MENU, self.onViewGrid,     id=MENU_VIEW_GRID)
        self.Bind(wx.EVT_MENU, self.onViewLegend,     id=MENU_LEGEND)
        self.Bind(wx.EVT_MENU, self.onHelp,         id=MENU_HELP)
        self.Bind(wx.EVT_MENU, self.onAbout,         id=MENU_ABOUT)
        self.Bind(wx.EVT_MENU, self.onBasicView,    id=MENU_BASIC)
        self.Bind(wx.EVT_MENU, self.onAdvancedView, id=MENU_ADVANCE)
        self.Bind(wx.EVT_MENU, self.onAdvanced3DView, id=MENU_3D)

    """ Menu event methods """
    def onViewLegend(self, event=None):
        if self.viewLegend:
            self.viewLegend = False
            self.Plot_Data()
        else:
            self.viewLegend = True
            # use proxy artist
            plot_op = Line2D([], [], linewidth=3, color="black") 
            plot_delta = Line2D([], [], linewidth=3, color="royalblue") 
            plot_gamma = Line2D([], [], linewidth=3, color="cyan") 
            plot_theta = Line2D([], [], linewidth=3, color="green") 
            plot_rho = Line2D([], [], linewidth=3, color="darkorange") 
            plot_risidual = Line2D([], [], linewidth=3, color="purple")

            # Shink current axis by 15%
            box = self.axes.get_position()
            self.axes.set_position([box.x0, box.y0, box.width * 0.88, box.height])
            # Put a legend to the right of the current axis
            self.axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'],
                loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})

            if self.current_view == 1:
                box = self.axes2.get_position()
                self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height])
                # Put a legend to the right of the current axis
                self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})
            self.canvas.draw()

    def onBasicView(self, event=None):
        self.current_view = 0
        # show sliders panel
        self.sliderPanel.Enable()
        self.toolbar.Enable()
        self.fillCheck.Enable()
        self.panel.Layout()
        self.Plot_Data()

    def onAdvancedView(self, event=None):
        self.current_view = 1
        # show sliders panel
        self.sliderPanel.Enable()
        self.toolbar.Enable()
        self.fillCheck.Enable()
        self.panel.Layout()
        self.Plot_Data()

    def onAdvanced3DView(self, event=None):
        self.current_view = 2
        # hide slider panel since will not be used
        self.sliderPanel.Disable()
        self.toolbar.Disable()
        self.fillCheck.Disable()
        self.panel.Layout()   
        self.Plot_Data()

    def onPrinterSetup(self,event=None):
        self.canvas.Printer_Setup(event=event)

    def onPrinterPreview(self,event=None):
        self.canvas.Printer_Preview(event=event)

    def onPrint(self,event=None):
        self.canvas.Printer_Print(event=event)

    def onClipboard(self,event=None):
        self.canvas.Copy_to_Clipboard(event=event)

    def onKeyEvent(self,event=None):
        """ capture and act upon keystroke events """
        if event == None: return
        key = event.GetKeyCode()
        if (key < wx.WXK_SPACE or  key > 255):  return

        if (event.ControlDown() and chr(key)=='C'): # Ctrl-C
            self.onClipboard(event=event)
        if (event.ControlDown() and chr(key)=='P'): # Ctrl-P
            self.onPrinterPreview(event=event)

    def onHelp(self, event=None):
        dlg = wx.MessageDialog(self, self.help_msg, "Quick Reference", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onAbout(self, event=None):
        dlg = wx.MessageDialog(self, self.about_msg, "About", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onViewGrid(self, event=None):
        if self.viewGrid:
            self.viewGrid = False
        else:
            self.viewGrid = True
        for a in self.fig.axes:
            a.grid(self.viewGrid)
        self.canvas.draw()

    def onExport(self,event=None):
        """ save figure image to file"""
        file_choices = "PNG (*.png)|*.png|" \
                       "JPEG (*.jpg)|*.jpg|" \
                       "BMP (*.bmp)|*.bmp"

        thisdir  = os.getcwd()

        dlg = wx.FileDialog(self, message='Save Plot Figure as...',
                            defaultDir = thisdir, defaultFile='plot.png',
                            wildcard=file_choices, style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path,dpi=300)
            if (path.find(thisdir) ==  0):
                path = path[len(thisdir)+1:]
            print('Saved plot to %s' % path)

    def onImport(self, event=None):
        """ Import csv file of option prices and greeks """
        file_choices = "SETTINGS (*.settings)|*.settings"
        thisdir  = ''.join(os.getcwd()+'/data')

        # import output file
        dlg = wx.FileDialog(self, message='Import option prices and greeks (Outputs)',
                            defaultDir = thisdir, defaultFile='data.settings',
                            wildcard=file_choices, style=wx.OPEN)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            projectDir = path.rsplit('/', 1)[0]
            #projectDir = path.rsplit('\\', 1)[0]
            self.reInitialiseData()
            
            # this also involves reading in all the data
            self.number_bumps = self.fileReader.loadSettingsFile(path, projectDir, self.statusbar)
            print('Opened settings file at %s' % path)
        else:
            dlg = wx.MessageDialog(self, "Failed to import the correct settings file.", "Complication", wx.OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        # populate data
        self.strike_price = self.fileReader.getStrikePrice()
        self.stock_price = self.fileReader.getStockPrice()
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), self.optionPriceCheck.IsChecked())
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), self.deltaCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), self.gammaCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), self.vegaCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), self.thetaCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), self.rhoCheck.IsChecked())

        self.onBasicView()

    def onExit(self,event=None):
        dlg = wx.MessageDialog(None, 'Are you sure to exit?', 'Confirm', wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION)
        ret = dlg.ShowModal()
        if ret == wx.ID_YES:
            self.Destroy()

    """ GUI event methods """
    def onShowFillEffect(self, event=None):
        if self.fillCheck.IsChecked():
            if self.differenceCheck.IsChecked():
                self.differenceCheck.SetValue(False)
                # reload and replot data
                self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
                    self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
                    self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
                #    self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
                    self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
                    self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
                self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
                    self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
            
            self.viewFill = True
        else:
            self.viewFill = False
        self.Plot_Data()

    def onCallRadio(self, event=None):
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), 
            self.optionPriceCheck.IsChecked())
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onPutRadio(self, event=None):
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), 
            self.optionPriceCheck.IsChecked())
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data() 

    def onOptionPrice(self, event=None):
        self.option_price = self.fileReader.getOptionPrice(self.callRadio.GetValue(), 
                self.optionPriceCheck.IsChecked())
        self.Plot_Data()

    def onDelta(self, event=None):
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onGamma(self, event=None):
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())

        self.Plot_Data()

    def onRho(self, event=None):
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onTheta(self, event=None):
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onVega(self, event=None):
        self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
            self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onRisidual(self, event=None):
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())

        # print(self.risidual)
        self.Plot_Data()

    def onShowEffects(self, event=None):
        if not self.effectCheck.IsChecked():
            warning_msg = """
                This setting will plot the value of the greeks, but not terms of the option price. This means that the greek graphs will no-longer be comparable. You will still be able to plot the greeks against each other though.

                Do you want to continue?
            """
            dlg = wx.MessageDialog(self, warning_msg, "Take Note", wx.YES_NO | wx.ICON_INFORMATION)
            ret = dlg.ShowModal()
            if ret == wx.ID_NO:
                dlg.Destroy()
                self.effectCheck.SetValue(True)
                return
            dlg.Destroy()
            self.differenceCheck.Disable()
            self.fillCheck.Disable()
            self.optionPriceCheck.SetValue(False)
            self.onOptionPrice()
            self.optionPriceCheck.Disable()
        else:
            self.differenceCheck.Enable()
            self.optionPriceCheck.Enable()
            if self.current_view != 2:
                self.fillCheck.Enable()

        # reload and replot data
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())

        self.Plot_Data()

    def onDifferenceCheck(self, event=None):
        if self.fillCheck.IsChecked():    
            self.fillCheck.SetValue(False)
            self.viewFill = False

        # reload and replot data
        self.delta = self.fileReader.getDeltaValues(self.callRadio.GetValue(), 
            self.deltaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.gamma = self.fileReader.getGammaValues(self.callRadio.GetValue(), 
            self.gammaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        # self.vega = self.fileReader.getVegaValues(self.callRadio.GetValue(), 
        #     self.vegaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.theta = self.fileReader.getThetaValues(self.callRadio.GetValue(), 
            self.thetaCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.rho = self.fileReader.getRhoValues(self.callRadio.GetValue(), 
            self.rhoCheck.IsChecked(), self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.risidual = self.fileReader.getRisidualValues(self.callRadio.GetValue(), self.risidualCheck.IsChecked(),
            self.differenceCheck.IsChecked(), self.effectCheck.IsChecked())
        self.Plot_Data()

    def onStockSlider(self, event=None):
        self.statusbar.SetStatusText("Stock price bump: "+str(self.stockSlider.GetValue()))
        self.stock_bump = self.stockSlider.GetValue()-1
        self.Plot_Data()

    def onRateSlider(self, event=None):
        self.statusbar.SetStatusText("Interest Rate bump: "+str(self.rateSlider.GetValue()))
        self.rate_bump = self.rateSlider.GetValue()-1
        self.Plot_Data()

    def onVolatilSlider(self, event=None):
        self.statusbar.SetStatusText("Volatility bump: "+str(self.volatilSlider.GetValue()))
        self.volitile_bump = self.volatilSlider.GetValue()-1
        self.Plot_Data()

    def ontimeStepSlider(self, event=None):
        self.statusbar.SetStatusText("Time step bump: "+str(self.timeStepSlider.GetValue()))
        self.time_bump = self.timeStepSlider.GetValue()-1
        self.Plot_Data()
        self.Plot_Data()

    """ Graph plotting methods """
    def clearPlots(self):
        """ Clear all graphs and plots for next draw """
        for a in self.fig.axes:
            self.fig.delaxes(a)

    def Plotter_2D_general(self, axes):
        # plot option price graph
        temp_option_price = []
        if len(self.option_price) > 0:
            temp_option_price = numpy.array(map(float, self.option_price[self.stock_bump]))
        if len(self.option_price) > 0:
            axes.plot(self.time, self.option_price[self.stock_bump], color='black')
        
        # stagger plot effects of greeks 
        temp_delta = []
        temp_gamma = []
        temp_theta = []
        temp_rho = []
        temp_risidual = []
        if len(self.delta) > 0:
            temp_delta = numpy.array(self.delta[self.stock_bump])
        if len(self.gamma) > 0:
            temp_gamma = numpy.array(self.gamma[self.stock_bump])
        if len(self.rho) > 0:
            temp_rho = numpy.array(self.rho[self.rate_bump])
        if len(self.theta) > 0:
            temp_theta = numpy.array(self.theta[self.time_bump])
        if len(self.risidual) > 0:
            temp_risidual = numpy.array(self.risidual[self.stock_bump])

        if not self.differenceCheck.IsChecked() and len(temp_option_price) > 0:
            for t in self.time:
                greeks_below = []
                greeks_above = []  # above/below option price
                if t < 30:
                    # sort arrays
                    if len(temp_delta) > 0:
                        if temp_delta[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_delta[t:t+2], 'delta'])
                        else:
                            greeks_below.append([temp_delta[t:t+2], 'delta'])
                    if len(temp_gamma) > 0:
                        if temp_gamma[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_gamma[t:t+2], 'gamma'])
                        else:
                            greeks_below.append([temp_gamma[t:t+2], 'gamma'])
                    if len(temp_theta) > 0:
                        if temp_theta[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_theta[t:t+2], 'theta'])
                        else:
                            greeks_below.append([temp_theta[t:t+2], 'theta'])
                    if len(temp_rho) > 0:
                        if temp_rho[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_rho[t:t+2], 'rho'])
                        else:
                            greeks_below.append([temp_rho[t:t+2], 'rho'])
                    if len(temp_risidual) > 0:
                        if temp_risidual[t+1] > temp_option_price[t+1]:
                            greeks_above.append([temp_risidual[t:t+2], 'risidual'])
                        else:
                            greeks_below.append([temp_risidual[t:t+2], 'risidual'])

                    temp_time = numpy.arange(t, t+2, 1)    
                    greeks_above = sorted(greeks_above, key=lambda tup: tup[0][1])
                    greeks_below = sorted(greeks_below, key=lambda tup: tup[0][1], reverse=True)

                    # PLOT stagger greek effects
                    temp_time = numpy.arange(t, t+2, 1)
                    temp1 = numpy.array(temp_option_price[t:t+2])

                    # print(t, greeks_below, greeks_above)
                    for g in greeks_above:
                        # print(t)
                        temp2 = numpy.array([temp_option_price[t], g[0][1]])
                        if self.viewFill and len(self.option_price) > 0:
                            if g[1] == 'delta':
                                axes.fill_between(temp_time, temp2, temp1, color='blue')
                            if g[1] == 'gamma':
                                axes.fill_between(temp_time, temp2, temp1, color='cyan')
                            if g[1] == 'theta':
                                axes.fill_between(temp_time, temp2, temp1, color='green')
                            if g[1] == 'rho':
                                axes.fill_between(temp_time, temp2, temp1, color='darkorange')
                            if g[1] == 'risidual':
                                axes.fill_between(temp_time, temp2, temp1, color='purple')
                        if g[1] == 'delta':
                            axes.plot(temp_time, temp2, label="Delta", color='blue')
                        if g[1] == 'gamma':
                            axes.plot(temp_time, temp2, label="Gamma", color='cyan')
                        if g[1] == 'theta':
                            axes.plot(temp_time, temp2, label="Theta", color='green')
                        if g[1] == 'rho':
                            axes.plot(temp_time, temp2, label="Rho", color='darkorange')
                        if g[1] == 'risidual':
                            axes.plot(temp_time, temp2, label="risidual", color='purple')
                        temp1 = temp2

                    temp1 = numpy.array(temp_option_price[t:t+2])
                    for g in greeks_below:
                        temp2 = numpy.array([temp_option_price[t], g[0][1]])
                        if self.viewFill and len(self.option_price) > 0:
                            if g[1] == 'delta':
                                axes.fill_between(temp_time, temp2, temp1, color='blue')
                            if g[1] == 'gamma':
                                axes.fill_between(temp_time, temp2, temp1, color='cyan')
                            if g[1] == 'theta':
                                axes.fill_between(temp_time, temp2, temp1, color='green')
                            if g[1] == 'rho':
                                axes.fill_between(temp_time, temp2, temp1, color='darkorange')
                            if g[1] == 'risidual':
                                axes.fill_between(temp_time, temp2, temp1, color='purple')
                        if g[1] == 'delta':
                            axes.plot(temp_time, temp2, label="Delta", color='blue')
                        if g[1] == 'gamma':
                            axes.plot(temp_time, temp2, label="Gamma", color='cyan')
                        if g[1] == 'theta':
                            axes.plot(temp_time, temp2, label="Theta", color='green')
                        if g[1] == 'rho':
                            axes.plot(temp_time, temp2, label="Rho", color='darkorange')
                        if g[1] == 'risidual':
                            axes.plot(temp_time, temp2, label="risidual", color='purple')
                        temp1 = temp2
        else:
            # plot difference between greeks and option price
            if len(self.delta) > 0:
                axes.plot(self.delta[self.stock_bump], color='blue')
            if len(self.gamma) > 0:
                axes.plot(self.gamma[self.stock_bump], color='cyan')
            # if len(self.vega) > 0:
            #    axes.plot(self.vega[self.volitile_bump], label="Vega", color='yellow')
            if len(self.theta) > 0:
                axes.plot(self.time, self.theta[self.time_bump], color='green')
            if len(self.rho) > 0:
                axes.plot(self.time, self.rho[self.rate_bump], color='darkorange')
            if len(self.risidual) > 0:
                axes.plot(self.time, self.risidual[self.stock_bump], color='purple')

        if self.viewLegend:
            # use proxy artist
            plot_op = Line2D([], [], linewidth=3, color="black") 
            plot_delta = Line2D([], [], linewidth=3, color="royalblue") 
            plot_gamma = Line2D([], [], linewidth=3, color="cyan") 
            plot_theta = Line2D([], [], linewidth=3, color="green") 
            plot_rho = Line2D([], [], linewidth=3, color="darkorange") 
            plot_risidual = Line2D([], [], linewidth=3, color="purple")

            # Shink current axis by 15%
            box = axes.get_position()
            axes.set_position([box.x0, box.y0, box.width * 0.88, box.height])
            # Put a legend to the right of the current axis
            axes.legend([plot_op, plot_delta, plot_gamma, plot_theta, plot_rho, plot_risidual], ['Option Price', 'Delta', 'Gamma', 'Theta', 'Rho', 'Residual'],
                loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})

    def Plot_Data(self):
        if self.current_view == 1:
            self.Plot_Data_advanced()
        elif self.current_view == 2:
            self.Plot_Data_3D()
        elif self.current_view == 0:            
            """ Basic 2D graph plotter """
            self.clearPlots()
            
            self.axes = self.fig.add_subplot(111) # can use add_axes, but then nav-toolbar would not work
            self.axes.set_xlim(0, 30)
            self.axes.grid(self.viewGrid)

            self.Plotter_2D_general(self.axes)

            # set caption and axes labels
            self.axes.set_xlabel('Time (Daily)')
            if self.effectCheck.IsChecked():
                self.axes.set_ylabel('Price (Rands)')
                if hasattr(self, 'title'):
                    self.title.set_text('Option Prices and breakdown of the effects of Greeks')
                else:
                    self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks')
            else:
                self.axes.set_ylabel('Greek Value')
                if hasattr(self, 'title'):
                    self.title.set_text('Raw Greek values not in terms of option price')
                else:
                    self.title = self.fig.suptitle('Greek values not in terms of option price')

            self.canvas.draw()

    def Plot_Data_advanced(self):
        """ Advanced 2D plotter """
        self.clearPlots()
        self.axes2 = self.fig.add_subplot(212)
        self.axes = self.fig.add_subplot(211, sharex=self.axes2)
        self.axes.set_xlim(0, 30)
        self.axes.grid(self.viewGrid)        
        self.axes2.grid(self.viewGrid)

        self.Plotter_2D_general(self.axes)

        # plot strike price and stock price curve
        if self.strike_price > 0:
            self.axes2.plot([0, 30], [self.strike_price, self.strike_price], label="Strike Price", color='red')

        # plot stock price curve
        temp_stock_price = numpy.array(self.stock_price)
        if len(temp_stock_price) > 0:
            self.axes2.plot(self.time, temp_stock_price, label="Stock Price", color='blue')

        # set limits for x and y axes
        # self.axes2.set_xlim(self.time_span_fill[0], self.time_span_fill[-1])
        # self.axes2.set_ylim(min(p, key=float), max(p, key=float))

        # set caption and axes labels
        self.axes2.set_xlabel('Time (Daily)')
        self.axes2.set_ylabel('Price (Rands)')
        if self.effectCheck.IsChecked():
            self.axes.set_ylabel('Price (Rands)')
            if hasattr(self, 'title'):
                self.title.set_text('Option Prices and breakdown of the effects of Greeks')
            else:
                self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks')
        else:
            self.axes.set_ylabel('Greek Value')
            if hasattr(self, 'title'):
                self.title.set_text('Raw Greek values not in terms of option price')
            else:
                self.title = self.fig.suptitle('Greek values not in terms of option price')

        # set useblit True on gtkagg for enhanced performance
        # self.span = SpanSelector(self.axes, self.onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red'))

        if self.viewLegend:
            # Shink current axis by 15%
            box = self.axes2.get_position()
            self.axes2.set_position([box.x0, box.y0, box.width * 0.88, box.height])
            # Put a legend to the right of the current axis
            self.axes2.legend(loc='center left', bbox_to_anchor=(1, 0.5), prop={'size':8})

        self.canvas.draw()

    def Plot_Data_3D(self):
        """ Advanced 3D plotter """
        # plot graphs
        self.clearPlots()
            
        self.axes = self.fig.add_subplot(111, projection='3d') # can use add_axes, but then nav-toolbar would not work
        self.axes.grid(self.viewGrid)

        b = numpy.arange(0, 9, 1)
        X2D, Y2D = numpy.meshgrid(self.time, b)
        Z2D = None
        
        # plot option price surface
        if len(self.option_price) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.option_price]            
            surf = self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, cmap=cm.afmhot, zorder=0.5)  #cm.coolwarm, cm.winter, cm.autumn
            cbar = self.fig.colorbar(surf, shrink=0.5, aspect=5)
            cbar.set_label('Option Price', rotation=90)

            ### TODO - mayavi ###
            # X2D, Y2D = numpy.mgrid[self.time, b]
            # print(X2D)
            # s = mlab.surf(Z2D)
            # mlab.show()

        # plot greek surfaces
        if len(self.delta) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.delta]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='blue')

        if len(self.gamma) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.gamma]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='cyan')
                
        if len(self.theta) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.theta]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='green')
                
        if len(self.rho) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.rho]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='orange')
                
        # if len(self.vega) > 0:
        #     Z2D = [[float(string) for string in inner] for inner in self.vega]
        #     self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
        #         antialiased=False, alpha=0.75, color='aqua')

        if len(self.risidual) > 0:
            Z2D = [[float(string) for string in inner] for inner in self.risidual]
            self.axes.plot_surface(X2D, Y2D, Z2D, rstride=1, cstride=1,
                antialiased=False, alpha=0.75, color='rosybrown')
        
        if Z2D != None:
            # cset1 = self.axes.contourf(X2D, Y2D, Z2D, zdir='z', offset=300, cmap=cm.afmhot)
            self.axes.contourf(X2D, Y2D, Z2D, zdir='x', offset=0, cmap=cm.coolwarm)
            self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=-0.3, cmap=cm.winter)
            # cset = self.axes.contour(X2D, Y2D, Z2D, zdir='y', offset=10, cmap=cm.afmhot)
            # cbar = self.fig.colorbar(cset1, shrink=0.7, aspect=3)
            # cbar = self.fig.colorbar(cset2, shrink=0.7, aspect=3)
            # cbar = self.fig.colorbar(cset3, shrink=0.5, aspect=5)
            # cbar.set_label('Option Proce', rotation=90)

        # set captions and axis labels
        self.axes.set_xlabel('Time (Days)')
        self.axes.set_xlim(0, 35)
        self.axes.set_ylabel('Bump Size')
        #~ self.axes.set_ylim(-3, 8)
        # self.axes.set_zlabel('Price (Rands)')
        # ~ self.axes.set_zlim(-100, 100)

        if self.effectCheck.IsChecked():
            if self.differenceCheck.IsChecked():
                self.axes.set_zlabel('Greek Value')
            else:
                self.axes.set_zlabel('Price (Rands)')
            if hasattr(self, 'title'):
                self.title.set_text('Option Prices and breakdown of the effects of Greeks')
            else:
                self.title = self.fig.suptitle('Option Prices and breakdown of the effects of Greeks')
        else:
            self.axes.set_zlabel('Greek Value')
            if hasattr(self, 'title'):
                self.title.set_text('Raw Greek values not in terms of option price')
            else:
                self.title = self.fig.suptitle('Greek values not in terms of option price')

        self.canvas.draw()
Exemple #45
0
class Spectra(ttk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.parent = parent
        self.grid(column=0, row=0, sticky='nwse')
        tk.Grid.columnconfigure(self, 1, weight=1)
        tk.Grid.rowconfigure(self, 8, weight=1)

        # Spectra name
        s_name_frame = ttk.LabelFrame(self, text="Spectra type:")
        s_name_frame.grid(column=0, row=0)
        self.s_name = tk.StringVar()
        self.s_name_radio = {}
        names = 'IR UV Raman VCD ECD ROA'.split(' ')
        values = 'ir uv raman vcd ecd roa'.split(' ')
        positions = [(c, r) for c in range(2) for r in range(3)]
        for n, v, (c, r) in zip(names, values, positions):
            b = ttk.Radiobutton(s_name_frame,
                                text=n,
                                variable=self.s_name,
                                value=v,
                                command=lambda v=v: self.spectra_chosen(v))
            b.configure(state='disabled')
            b.grid(column=c, row=r, sticky='w', padx=5)
            self.s_name_radio[v] = b

        # Settings
        sett = ttk.LabelFrame(self, text="Settings:")
        sett.grid(column=0, row=1, sticky='we')
        tk.Grid.columnconfigure(sett, (1, 2), weight=1)
        ttk.Label(sett, text='Fitting').grid(column=0, row=0)
        fit = tk.StringVar()
        self.fitting = ttk.Combobox(sett,
                                    textvariable=fit,
                                    state='disabled',
                                    width=13)
        self.fitting.bind('<<ComboboxSelected>>', self.live_preview_callback)
        self.fitting.var = fit
        self.fitting.grid(column=1, row=0, columnspan=2, sticky='e')
        self.fitting['values'] = ('lorentzian', 'gaussian')
        guicom.WgtStateChanger.bars.append(self.fitting)
        for no, name in enumerate(
                'Start Stop Step Width Offset Scaling'.split(' ')):
            ttk.Label(sett, text=name).grid(column=0, row=no + 1)
            var = tk.StringVar()
            entry = ttk.Entry(sett,
                              textvariable=var,
                              width=10,
                              state='disabled',
                              validate='key',
                              validatecommand=self.parent.validate_entry)
            entry.bind('<FocusOut>',
                       lambda e, var=var:
                       (self.parent.entry_out_validation(var),
                        self.live_preview_callback()))
            setattr(self, name.lower(), entry)
            entry.var = var
            entry.grid(column=1, row=no + 1, sticky='e')
            unit = tk.StringVar()
            unit.set('-')
            entry.unit = unit
            label = ttk.Label(sett, textvariable=unit)
            label.grid(column=2, row=no + 1, sticky='e')
            guicom.WgtStateChanger.bars.append(entry)

        # Calculation Mode
        self.mode = tk.StringVar()
        self.single_radio = ttk.Radiobutton(self,
                                            text='Single file',
                                            variable=self.mode,
                                            value='single',
                                            state='disabled',
                                            command=self.mode_chosen)
        self.single_radio.grid(column=0, row=2, sticky='w')
        self.average_radio = ttk.Radiobutton(self,
                                             text='Average by energy',
                                             variable=self.mode,
                                             value='average',
                                             state='disabled',
                                             command=self.mode_chosen)
        self.average_radio.grid(column=0, row=3, sticky='w')
        self.stack_radio = ttk.Radiobutton(self,
                                           text='Stack by overview',
                                           variable=self.mode,
                                           value='stack',
                                           state='disabled',
                                           command=self.mode_chosen)
        self.stack_radio.grid(column=0, row=4, sticky='w')

        self.single = tk.StringVar()
        self.single.set('Choose conformer...')
        self.single_box = ttk.Combobox(self,
                                       textvariable=self.single,
                                       state='disabled')
        self.single_box.bind(
            '<<ComboboxSelected>>',
            lambda event: self.live_preview_callback(event, mode='single'))
        # self.single_box.grid(column=0, row=3)
        self.single_box['values'] = ()
        self.average = tk.StringVar()
        self.average.set('Choose energy...')
        self.average_box = ttk.Combobox(self,
                                        textvariable=self.average,
                                        state='disabled')
        self.average_box.bind(
            '<<ComboboxSelected>>',
            lambda event: self.live_preview_callback(event, mode='average'))
        # self.average_box.grid(column=0, row=5)
        average_names = 'Thermal Enthalpy Gibbs SCF Zero-Point'.split(' ')
        self.average_box['values'] = average_names
        average_keys = 'ten ent gib scf zpe'.split(' ')
        self.average_ref = {k: v for k, v in zip(average_names, average_keys)}
        self.stack = tk.StringVar()
        self.stack.set('Choose colour...')
        self.stack_box = ttk.Combobox(self,
                                      textvariable=self.stack,
                                      state='disabled')
        self.stack_box.bind('<<ComboboxSelected>>', self.change_colour)
        # self.stack_box.grid(column=0, row=7)
        self.stack_box['values'] = ('Blues Reds Greens spring summer autumn '
                                    'winter copper ocean rainbow '
                                    'nipy_spectral gist_ncar'.split(' '))
        guicom.WgtStateChanger.bars.extend([
            self.single_radio, self.single_box, self.stack_radio,
            self.stack_box
        ])
        guicom.WgtStateChanger.both.extend(
            [self.average_radio, self.average_box])
        self.boxes = dict(single=self.single_box,
                          average=self.average_box,
                          stack=self.stack_box)
        self.current_box = None

        # Live preview
        # Recalculate
        frame = ttk.Frame(self)
        frame.grid(column=0, row=8, sticky='n')
        var = tk.BooleanVar()
        var.set(False)
        self.reverse_ax = ttk.Checkbutton(frame,
                                          variable=var,
                                          text='Reverse x-axis',
                                          state='disabled',
                                          command=self.live_preview_callback)
        self.reverse_ax.grid(column=0, row=0, sticky='w')
        self.reverse_ax.var = var
        var = tk.BooleanVar()
        var.set(True)
        self.show_bars = ttk.Checkbutton(frame,
                                         variable=var,
                                         text='Show bars',
                                         state='disabled',
                                         command=self.live_preview_callback)
        self.show_bars.grid(column=0, row=1, sticky='w')
        self.show_bars.var = var
        self.show_bars.previous_value = True
        var = tk.BooleanVar()
        var.set(False)
        self.show_exp = ttk.Checkbutton(frame,
                                        variable=var,
                                        text='Experimental',
                                        state='disabled',
                                        command=self.live_preview_callback)
        self.show_exp.grid(column=0, row=2, sticky='w')
        self.show_exp.var = var
        self.load_exp = ttk.Button(
            frame,
            text='Load...',
            state='disabled',
            command=lambda:
            (self.load_exp_command(), self.live_preview_callback()))
        self.load_exp.grid(column=1, row=2)
        var = tk.BooleanVar()
        var.set(True)
        self.live_prev = ttk.Checkbutton(frame,
                                         variable=var,
                                         text='Live preview',
                                         state='disabled')
        self.live_prev.grid(column=0, row=3, sticky='w')
        self.live_prev.var = var
        # previously labeled 'Recalculate'
        self.recalc_b = ttk.Button(frame,
                                   text='Redraw',
                                   state='disabled',
                                   command=self.recalculate_command)
        self.recalc_b.grid(column=1, row=3)
        guicom.WgtStateChanger.bars.extend([self.live_prev, self.recalc_b])

        # Spectrum
        spectra_view = ttk.LabelFrame(self, text='Spectra view')
        spectra_view.grid(column=1, row=0, rowspan=10, sticky='nwse')
        tk.Grid.columnconfigure(spectra_view, 0, weight=1)
        tk.Grid.rowconfigure(spectra_view, 0, weight=1)
        self.figure = Figure()
        # ensure proper plot resizing
        self.bind('<Configure>', lambda event: self.figure.tight_layout())
        self.canvas = FigureCanvasTkAgg(self.figure, master=spectra_view)
        # self.canvas.draw()
        self.canvas.get_tk_widget().grid(column=0, row=0, sticky='nwse')
        self.tslr_ax = None
        self.bars_ax = None
        self.exp_ax = None
        self.last_used_settings = {
            name: {
                'offset': 0,
                'scaling': 1,
                'show_bars': True,
                'show_exp': False,
                'reverse_ax': name not in ('uv', 'ecd')
            }
            for name in self.s_name_radio
        }
        self._exp_spc = {k: None for k in self.s_name_radio.keys()}
        # TO DO:
        # add save/save img buttons

    @property
    def exp_spc(self):
        return self._exp_spc[self.s_name.get()]

    @exp_spc.setter
    def exp_spc(self, value):
        self._exp_spc[self.s_name.get()] = value

    def load_exp_command(self):
        filename = askopenfilename(
            parent=self,
            title='Select spectrum file.',
            filetypes=[
                ("text files", "*.txt"),
                ("xy files", "*.xy"),
                # ("spc files", "*.spc"),
                # spc not supported yet
                ("all files", "*.*")
            ])
        if filename:
            try:
                spc = self.parent.tslr.soxhlet.load_spectrum(filename)
                self.exp_spc = spc
            except ValueError:
                logger.warning(
                    "Experimental spectrum couldn't be loaded. "
                    "Please check if format of your file is supported"
                    " or if file is not corrupted.")
        else:
            return

    def mode_chosen(self, event=None):
        mode = self.mode.get()
        if self.current_box is not None:
            self.current_box.grid_forget()
        self.current_box = self.boxes[mode]
        self.current_box.grid(column=0, row=5)
        if mode == 'single':
            self.show_bars.config(state='normal')
            self.show_bars.var.set(self.show_bars.previous_value)
        else:
            self.show_bars.config(state='disabled')
            self.show_bars.previous_value = self.show_bars.var.get()
            self.show_bars.var.set(False)
        self.live_preview_callback()

    def spectra_chosen(self, event=None):
        tslr = self.parent.tslr
        self.visualize_settings()
        bar = tesliper.gw.default_spectra_bars[self.s_name.get()]
        self.single_box['values'] = [
            k for k, v in tslr.molecules.items() if bar in v
        ]
        self.reverse_ax.config(state='normal')
        self.load_exp.config(state='normal')
        self.show_exp.config(state='normal')
        if self.mode.get():
            self.live_preview_callback()
        else:
            self.single_radio.invoke()

    def visualize_settings(self):
        spectra_name = self.s_name.get()
        spectra_type = tesliper.gw.Bars.spectra_type_ref[spectra_name]
        tslr = self.parent.tslr
        last_used = self.last_used_settings[spectra_name]
        settings = tslr.parameters[spectra_type].copy()
        settings.update(last_used)
        for name, sett in settings.items():
            if name == 'fitting':
                try:
                    self.fitting.var.set(settings['fitting'].__name__)
                except AttributeError:
                    self.fitting.var.set(settings['fitting'])
            else:
                entry = getattr(self, name)
                entry.var.set(sett)
                try:
                    entry.unit.set(
                        tesliper.gw.Spectra._units[spectra_name][name])
                except AttributeError:
                    logger.debug(f"Pass on {name}")
                except KeyError:
                    if name == 'offset':
                        entry.unit.set(
                            tesliper.gw.Spectra._units[spectra_name]['start'])
                    elif name == 'scaling':
                        pass
                    else:
                        raise ValueError(f'Invalid setting name: {name}')

    def live_preview_callback(self, event=None, mode=False):
        # TO DO: separate things, that don't need recalculation
        # TO DO: show/hide bars/experimental plots when checkbox clicked
        # TO DO: rewrite this function with sense
        spectra_name = self.s_name.get()
        mode_con = self.mode.get() == mode if mode else True
        settings_con = spectra_name not in self.last_used_settings or \
            self.current_settings != self.last_used_settings[spectra_name]
        core = any([not self.tslr_ax, mode_con, settings_con])
        if all([core, self.live_prev.var.get(), self.mode.get()]):
            # self.mode.get() unnecessary because included in mode_con?
            self.recalculate_command()

    def new_plot(self):
        if self.tslr_ax:
            self.figure.delaxes(self.tslr_ax)
            self.tslr_ax = None
        if self.bars_ax:
            self.figure.delaxes(self.bars_ax)
            self.bars_ax = None
        if self.exp_ax:
            self.figure.delaxes(self.exp_ax)
            self.exp_ax = None

    def align_axes(self, axes, values):
        """Align zeros of the axes, zooming them out by same ratio"""
        # based on https://stackoverflow.com/a/46901839
        if not len(values) == len(axes):
            raise ValueError(
                f"Number of values ({len(values)}) different than number of"
                f"axes ({len(axes)}).")
        extrema = [[min(v), max(v)] for v in values]
        # upper and lower limits
        lowers, uppers = zip(*extrema)
        all_positive = min(lowers) > 0
        all_negative = max(uppers) < 0
        # reset for divide by zero issues
        lowers = [1 if math.isclose(l, 0.0) else l for l in lowers]
        uppers = [-1 if math.isclose(u, 0.0) else u for u in uppers]
        # pick "most centered" axis
        res = [abs(u + l) for l, u in zip(lowers, uppers)]
        min_index = res.index(min(res))
        # scale positive or negative part
        multiplier1 = -abs(uppers[min_index] / lowers[min_index])
        multiplier2 = -abs(lowers[min_index] / uppers[min_index])
        lower_lims, upper_lims = [], []
        for i, (low, up) in enumerate(extrema):
            # scale positive or negative part based on which induces valid
            if i != min_index:
                lower_change = up * multiplier2
                upper_change = low * multiplier1
                if upper_change < up:
                    lower_lims.append(lower_change)
                    upper_lims.append(up)
                else:
                    lower_lims.append(low)
                    upper_lims.append(upper_change)
            else:
                lower_lims.append(low)
                upper_lims.append(up)
        # bump by 10% for a margin
        if all_positive:
            lower_lims = [0 for _ in range(len(lower_lims))]
        if all_negative:
            upper_lims = [0 for _ in range(len(upper_lims))]
        diff = [abs(u - l) for l, u in zip(lower_lims, upper_lims)]
        margin = [x * .05 for x in diff]
        lower_lims = [lim - m for lim, m in zip(lower_lims, margin)]
        upper_lims = [lim + m for lim, m in zip(upper_lims, margin)]
        # set axes limits
        [
            ax.set_ylim(low, up)
            for ax, low, up in zip(axes, lower_lims, upper_lims)
        ]

    def show_spectra(self,
                     spc,
                     bars=None,
                     colour=None,
                     width=0.5,
                     stack=False):
        # TO DO: correct spectra drawing when offset used
        spc.offset = float(self.offset.var.get())
        spc.scaling = float(self.scaling.var.get())
        self.new_plot()
        self.tslr_ax = tslr_ax = self.figure.add_subplot(111)
        tslr_ax.set_xlabel(spc.units['x'])
        tslr_ax.set_ylabel(spc.units['y'])
        tslr_ax.hline = tslr_ax.axhline(color='lightgray', lw=width)
        if stack:
            col = cm.get_cmap(colour)
            no = len(spc.y)
            x = spc.x
            for num, y_ in enumerate(spc.y):
                tslr_ax.plot(x, y_, lw=width, color=col(num / no))
        else:
            tslr_ax.plot(spc.x, spc.y, lw=width, color='k')
            values = [spc.y]
            axes = [tslr_ax]
            if self.show_bars.var.get() and bars is not None:
                self.bars_ax = bars_ax = tslr_ax.twinx()
                freqs = bars.wavelengths[0] if spc.genre in ('uv', 'ecd') \
                    else bars.frequencies[0]
                freqs = freqs + spc.offset
                # show only bars within range requested in calculations
                blade = (freqs >= min(spc.x)) & (freqs <= max(spc.x))
                markerline, stemlines, baseline = bars_ax.stem(
                    freqs[blade],
                    bars.values[0][blade],
                    linefmt='b-',
                    markerfmt=' ',
                    basefmt=' ')
                for line in stemlines:
                    line.set_linewidth(width)
                bars_ax.set_ylabel(bars.units)
                bars_ax.tick_params(axis='y', colors='b')
                values.append(bars.values[0])
                axes.append(bars_ax)
            if self.show_exp.var.get() and self.exp_spc is not None:
                maxes = [max(self.exp_spc[1]), max(spc.y)]
                if min(maxes) / max(maxes) > 0.4:
                    # if both will fit fine in one plot
                    tslr_ax.plot(*self.exp_spc, lw=width, color='r')
                    values[0] = maxes + [min(self.exp_spc[1]), min(spc.y)]
                else:
                    self.exp_ax = exp_ax = tslr_ax.twinx()
                    exp_ax.plot(*self.exp_spc, lw=width, color='r')
                    exp_ax.spines["left"].set_position(("axes", -0.1))
                    exp_ax.spines["left"].set_visible(True)
                    exp_ax.yaxis.set_ticks_position('left')
                    exp_ax.tick_params(axis='y', colors='r')
                    tslr_ax.yaxis.set_label_coords(-0.17, 0.5)
                    # tslr_ax.tick_params(axis='y', colors='navy')
                    values.append(self.exp_spc[1])
                    axes.append(exp_ax)
            self.align_axes(axes, values)
        if self.reverse_ax.var.get():
            tslr_ax.invert_xaxis()
        self.figure.tight_layout()
        self.canvas.draw()

    def average_draw(self, spectra_name, option):
        # TO DO: ensure same conformers are taken into account
        self._calculate_spectra(spectra_name, option, 'average')
        queue_ = self.parent.thread.queue
        self._show_spectra(queue_)

    def single_draw(self, spectra_name, option):
        self._calculate_spectra(spectra_name, option, 'single')
        bar_name = tesliper.gw.default_spectra_bars[spectra_name]
        with self.parent.tslr.molecules.trimmed_to([option]):
            bars = self.parent.tslr[bar_name]
        queue_ = self.parent.thread.queue
        self._show_spectra(queue_, bars=bars)

    def stack_draw(self, spectra_name, option):
        # TO DO: color of line depending on population
        self._calculate_spectra(spectra_name, option, 'stack')
        if self.tslr_ax:
            self.figure.delaxes(self.tslr_ax)
        self.tslr_ax = self.figure.add_subplot(111)
        queue_ = self.parent.thread.queue
        self._show_spectra(queue_, colour=option, stack=True)

    def change_colour(self, event=None):
        if not self.tslr_ax or self.mode.get() != 'stack':
            return
        colour = self.stack.get()
        col = cm.get_cmap(colour)
        self.tslr_ax.hline.remove()
        lines = self.tslr_ax.get_lines()
        no = len(lines)
        for num, line in enumerate(lines):
            line.set_color(col(num / no))
        self.tslr_ax.hline = self.tslr_ax.axhline(color='lightgray', lw=0.5)
        self.canvas.draw()

    def _show_spectra(self,
                      queue_,
                      bars=None,
                      colour=None,
                      width=0.5,
                      stack=False):
        try:
            spc = queue_.get(0)  # data put to queue by self._calculate_spectra
            self.show_spectra(spc,
                              bars=bars,
                              colour=colour,
                              width=width,
                              stack=stack)
        except queue.Empty:
            self.after(20, self._show_spectra, queue_, bars, colour, width,
                       stack)

    @guicom.Feedback("Calculating...")
    def _calculate_spectra(self, spectra_name, option, mode):
        tslr = self.parent.tslr
        if mode == 'single':
            spc = tslr.calculate_single_spectrum(spectra_name=spectra_name,
                                                 conformer=option,
                                                 **self.calculation_params)
        else:
            spc = tslr.calculate_spectra(
                spectra_name, **self.calculation_params)[
                    spectra_name]  # tslr.calculate_spectra returns dictionary
            if mode == 'average':
                en_name = self.average_ref[option]
                spc = tslr.get_averaged_spectrum(spectra_name, en_name)
        return spc

    @property
    def calculation_params(self):
        d = {
            k: v
            for k, v in self.current_settings.items()
            if k in 'start stop step width fitting'.split(' ')
        }
        return d

    @property
    def current_settings(self):
        try:
            settings = {
                key: float(getattr(self, key).get())
                for key in 'start stop step width offset scaling'.split(' ')
            }
            settings.update({
                key: getattr(self, key).var.get()
                for key in 'reverse_ax show_bars show_exp'.split(' ')
            })
            fit = self.fitting.get()
            settings['fitting'] = getattr(tesliper.dw, fit)
        except ValueError:
            return {}
        return settings

    def recalculate_command(self):
        spectra_name = self.s_name.get()
        if not spectra_name:
            logger.debug('spectra_name not specified.')
            return
        self.last_used_settings[spectra_name] = self.current_settings.copy()
        mode = self.mode.get()
        # get value of self.single, self.average or self.stack respectively
        option = getattr(self, mode).get()
        if option.startswith('Choose '):
            return
        logger.debug("Recalculating!")
        self.new_plot()
        # call self.single_draw, self.average_draw or self.stack_draw
        # respectively
        drawers = {
            'single': self.single_draw,
            'average': self.average_draw,
            'stack': self.stack_draw
        }
        spectra_drawer = drawers[mode]
        spectra_drawer(spectra_name, option)
class PlotView(QtWidgets.QWidget):
    subplotRemovedSignal = QtCore.Signal(object)
    plotCloseSignal = QtCore.Signal()

    def __init__(self):
        super(PlotView, self).__init__()
        self.plots = OrderedDict({})
        self.errors_list = set()
        self.plot_storage = {}  # stores lines and info to create lines
        self.current_grid = None
        self.gridspecs = {
            1: gridspec.GridSpec(1, 1),
            2: gridspec.GridSpec(1, 2),
            3: gridspec.GridSpec(3, 1),
            4: gridspec.GridSpec(2, 2)
        }
        self.figure = Figure()
        self.figure.set_facecolor("none")
        self.canvas = FigureCanvas(self.figure)

        self.plot_selector = QtWidgets.QComboBox()
        self._update_plot_selector()
        self.plot_selector.currentIndexChanged[str].connect(self._set_bounds)

        button_layout = QtWidgets.QHBoxLayout()
        self.x_axis_changer = AxisChangerPresenter(AxisChangerView("X"))
        self.x_axis_changer.on_upper_bound_changed(self._update_x_axis_upper)
        self.x_axis_changer.on_lower_bound_changed(self._update_x_axis_lower)

        self.y_axis_changer = AxisChangerPresenter(AxisChangerView("Y"))
        self.y_axis_changer.on_upper_bound_changed(self._update_y_axis_upper)
        self.y_axis_changer.on_lower_bound_changed(self._update_y_axis_lower)

        self.errors = QtWidgets.QCheckBox("Errors")
        self.errors.stateChanged.connect(self._errors_changed)

        button_layout.addWidget(self.plot_selector)
        button_layout.addWidget(self.x_axis_changer.view)
        button_layout.addWidget(self.y_axis_changer.view)
        button_layout.addWidget(self.errors)

        grid = QtWidgets.QGridLayout()

        self.toolbar = myToolbar(self.canvas, self)
        self.toolbar.update()

        grid.addWidget(self.toolbar, 0, 0)
        grid.addWidget(self.canvas, 1, 0)
        grid.addLayout(button_layout, 2, 0)
        self.setLayout(grid)

    def setAddConnection(self, slot):
        self.toolbar.setAddConnection(slot)

    def setRmConnection(self, slot):
        self.toolbar.setRmConnection(slot)

    def _redo_layout(func):
        """
        Simple decorator (@_redo_layout) to call tight_layout() on plots
         and to redraw the canvas.
        (https://www.python.org/dev/peps/pep-0318/)
        """

        def wraps(self, *args, **kwargs):
            output = func(self, *args, **kwargs)
            if len(self.plots):
                self.figure.tight_layout()
            self.canvas.draw()
            return output
        return wraps

    def _silent_checkbox_check(self, state):
        """ Checks a checkbox without emitting a checked event. """
        self.errors.blockSignals(True)
        self.errors.setChecked(state)
        self.errors.blockSignals(False)

    def _set_plot_bounds(self, name, plot):
        """
        Sets AxisChanger bounds to the given plot bounds and updates
            the plot-specific error checkbox.
        """
        self.x_axis_changer.set_bounds(plot.get_xlim())
        self.y_axis_changer.set_bounds(plot.get_ylim())
        self._silent_checkbox_check(name in self.errors_list)

    def _set_bounds(self, new_plot):
        """
        Sets AxisChanger bounds if a new plot is added, or removes the AxisChanger
            fields if a plot is removed.
        """
        new_plot = str(new_plot)
        if new_plot and new_plot != "All":
            plot = self.get_subplot(new_plot)
            self._set_plot_bounds(new_plot, plot)
        elif not new_plot:
            self.x_axis_changer.clear_bounds()
            self.y_axis_changer.clear_bounds()

    def _get_current_plot_name(self):
        """ Returns the 'current' plot name based on the dropdown selector. """
        return str(self.plot_selector.currentText())

    def _get_current_plots(self):
        """
        Returns a list of the current plot, or all plots if 'All' is selected.
        """
        name = self._get_current_plot_name()
        return self.plots.values() if name == "All" else [
            self.get_subplot(name)]

    @_redo_layout
    def _update_x_axis(self, bound):
        """ Updates the plot's x limits with the specified bound. """
        try:
            for plot in self._get_current_plots():
                plot.set_xlim(**bound)
        except KeyError:
            return

    def _update_x_axis_lower(self, bound):
        """ Updates the lower x axis limit. """
        self._update_x_axis({"left": bound})

    def _update_x_axis_upper(self, bound):
        """ Updates the upper x axis limit. """
        self._update_x_axis({"right": bound})

    @_redo_layout
    def _update_y_axis(self, bound):
        """ Updates the plot's y limits with the specified bound. """
        try:
            for plot in self._get_current_plots():
                plot.set_ylim(**bound)
        except KeyError:
            return

    def _update_y_axis_lower(self, bound):
        """ Updates the lower y axis limit. """
        self._update_y_axis({"bottom": bound})

    def _update_y_axis_upper(self, bound):
        """ Updates the upper y axis limit. """
        self._update_y_axis({"top": bound})

    def _modify_errors_list(self, name, state):
        """
        Adds/Removes a plot name to the errors set depending on the 'state' bool.
        """
        if state:
            self.errors_list.add(name)
        else:
            try:
                self.errors_list.remove(name)
            except KeyError:
                return

    def _change_plot_errors(self, name, plot, state):
        """
        Removes the previous plot and redraws with/without errors depending on the state.
        """
        self._modify_errors_list(name, state)
        # get a copy of all the workspaces
        workspaces = copy(self.plot_storage[name].ws)
        # get the limits before replotting, so they appear unchanged.
        x, y = plot.get_xlim(), plot.get_ylim()
        # clear out the old container
        self.plot_storage[name].delete()
        for workspace in workspaces:
            self.plot(name, workspace)
        plot.set_xlim(x)
        plot.set_ylim(y)
        self._set_bounds(name)  # set AxisChanger bounds again.

    @_redo_layout
    def _errors_changed(self, state):
        """ Replots subplots with errors depending on the current selection. """
        current_name = self._get_current_plot_name()
        if current_name == "All":
            for name, plot in iteritems(self.plots):
                self._change_plot_errors(name, plot, state)
        else:
            self._change_plot_errors(
                current_name, self.get_subplot(current_name), state)

    def _set_positions(self, positions):
        """ Moves all subplots based on a gridspec change. """
        for plot, pos in zip(self.plots.values(), positions):
            grid_pos = self.current_grid[pos[0], pos[1]]
            plot.set_position(
                grid_pos.get_position(
                    self.figure))  # sets plot position, magic?
            # required because tight_layout() is used.
            plot.set_subplotspec(grid_pos)

    @_redo_layout
    def _update_gridspec(self, new_plots, last=None):
        """ Updates the gridspec; adds a 'last' subplot if one is supplied. """
        if new_plots:
            self.current_grid = self.gridspecs[new_plots]
            positions = putils.get_layout(new_plots)
            self._set_positions(positions)
            if last is not None:
                # label is necessary to fix
                # https://github.com/matplotlib/matplotlib/issues/4786
                pos = self.current_grid[positions[-1][0], positions[-1][1]]
                self.plots[last] = self.figure.add_subplot(pos, label=last)
                self.plots[last].set_subplotspec(pos)
        self._update_plot_selector()

    def _update_plot_selector(self):
        """ Updates plot selector (dropdown). """
        self.plot_selector.clear()
        self.plot_selector.addItem("All")
        self.plot_selector.addItems(list(self.plots.keys()))

    @_redo_layout
    def plot(self, name, workspace):
        """ Plots a workspace to a subplot (with errors, if necessary). """
        if name in self.errors_list:
            self.plot_workspace_errors(name, workspace)
        else:
            self.plot_workspace(name, workspace)
        self._set_bounds(name)

    def _add_plotted_line(self, name, label, lines, workspace):
        """ Appends plotted lines to the related subplot list. """
        self.plot_storage[name].addLine(label, lines, workspace)

    def plot_workspace_errors(self, name, workspace):
        """ Plots a workspace with errors, and appends caps/bars to the subplot list. """
        subplot = self.get_subplot(name)
        line, cap_lines, bar_lines = plots.plotfunctions.errorbar(
            subplot, workspace, specNum=1)
        # make a tmp plot to get auto generated legend name
        tmp, = plots.plotfunctions.plot(subplot, workspace, specNum=1)
        label = tmp.get_label()
        # remove the tmp line
        tmp.remove()
        del tmp
        # collect results
        all_lines = [line]
        all_lines.extend(cap_lines)
        all_lines.extend(bar_lines)
        self._add_plotted_line(name, label, all_lines, workspace)

    def plot_workspace(self, name, workspace):
        """ Plots a workspace normally. """
        subplot = self.get_subplot(name)
        line, = plots.plotfunctions.plot(subplot, workspace, specNum=1)
        self._add_plotted_line(name, line.get_label(), [line], workspace)

    def get_subplot(self, name):
        """ Returns the subplot corresponding to a given name """
        return self.plots[name]

    def get_subplots(self):
        """ Returns all subplots. """
        return self.plots

    def add_subplot(self, name):
        """ will raise KeyError if: plots exceed 4 """
        self._update_gridspec(len(self.plots) + 1, last=name)
        self.plot_storage[name] = subPlot(name)
        return self.get_subplot(name)

    def remove_subplot(self, name):
        """ will raise KeyError if: 'name' isn't a plot; there are no plots """
        self.figure.delaxes(self.get_subplot(name))
        del self.plots[name]
        del self.plot_storage[name]
        self._update_gridspec(len(self.plots))
        self.subplotRemovedSignal.emit(name)

    def removeLine(self, subplot, label):
        self.plot_storage[subplot].removeLine(label)

    @_redo_layout
    def add_moveable_vline(self, plot_name, x_value, y_minx, y_max, **kwargs):
        pass

    @_redo_layout
    def add_moveable_hline(self, plot_name, y_value, x_min, x_max, **kwargs):
        pass

    def closeEvent(self, event):
        self.plotCloseSignal.emit()

    def plotCloseConnection(self, slot):
        self.plotCloseSignal.connect(slot)

    @property
    def subplot_names(self):
        return self.plot_storage.keys()

    def line_labels(self, subplot):
        return self.plot_storage[subplot].lines.keys()
Exemple #47
0
class Interact(QtGui.QMainWindow):

    def __init__(self, data, app, title=None, sortkey=None, axisequal=False,
                 parent=None, **kwargs):
        self.app = app
        QtGui.QMainWindow.__init__(self, parent)
        if title is not None:
            self.setWindowTitle(title)
        else:
            self.setWindowTitle(', '.join(d[1] for d in data))
        if sortkey is not None:
            self.sortkey = sortkey
        else:
            self.sortkey = kwargs.get('key', lambda x: x.lower())
        self.grid = QtGui.QGridLayout()

        self.frame = QtGui.QWidget()
        self.dpi = 100

        self.fig = Figure(tight_layout=True)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.frame)
        self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas.mpl_connect('key_press_event', self.canvas_key_press)
        self.axes = self.fig.add_subplot(111)
        self.axes2 = self.axes.twinx()
        self.fig.delaxes(self.axes2)

        self.xlim = None
        self.ylim = None
        self.xlogscale = 'linear'
        self.ylogscale = 'linear'
        self.axisequal = axisequal
        self.margins = 0

        self.mpl_toolbar = NavigationToolbar(self.canvas, self.frame)
        self.pickers = None

        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addWidget(self.mpl_toolbar)

        self.props_editor = PropertyEditor(self)

        self.datas = []
        for d in data:
            self.add_data(*d)

        self.vbox.addLayout(self.grid)
        self.set_layout()

    def set_layout(self):
        self.vbox.addWidget(self.canvas)

        self.frame.setLayout(self.vbox)
        self.setCentralWidget(self.frame)

        for data in self.datas:
            self.setTabOrder(data.menu, data.scale_box)
            self.setTabOrder(data.scale_box, data.xmenu)
            self.setTabOrder(data.xmenu, data.xscale_box)

        if len(self.datas) >= 2:
            for d1, d2 in zip(self.datas[:-1], self.datas[1:]):
                self.setTabOrder(d1.menu, d2.menu)

        self.draw()

    def add_data(self, obj, name, kwargs=None):
        kwargs = kwargs or {}
        kwargs['name'] = kwargs.get('name', name) or 'data'
        self.datas.append(DataObj(self, obj, **kwargs))
        data = self.datas[-1]

        self.row = self.grid.rowCount()
        self.column = 0

        def axisequal():
            self.axisequal = not self.axisequal
            self.draw()

        def add_widget(w, axis=None):
            self.grid.addWidget(w, self.row, self.column)
            data.widgets.append(w)
            self.connect(w, SIGNAL('duplicate()'), data.duplicate)
            self.connect(w, SIGNAL('remove()'), data.remove)
            self.connect(w, SIGNAL('closed()'), data.close)
            self.connect(w, SIGNAL('axisequal()'), axisequal)
            self.connect(w, SIGNAL('relabel()'), data.change_label)
            self.connect(w, SIGNAL('edit_props()'), data.edit_props)
            self.connect(w, SIGNAL('sync()'), data.sync)
            self.connect(w, SIGNAL('twin()'), data.toggle_twin)
            self.connect(w, SIGNAL('xlim()'), self.set_xlim)
            self.connect(w, SIGNAL('ylim()'), self.set_ylim)
            if axis:
                self.connect(w, SIGNAL('sync_axis()'),
                             lambda axes=[axis]: data.sync(axes))
            self.column += 1

        add_widget(data.label)
        add_widget(data.menu, 'y')
        add_widget(data.scale_label)
        add_widget(data.scale_box, 'y')
        add_widget(data.xlabel)
        add_widget(data.xmenu, 'x')
        add_widget(data.xscale_label)
        add_widget(data.xscale_box, 'x')

    def warn(self, message):
        self.warnings = [message]
        self.draw_warnings()
        self.canvas.draw()

    def remove_data(self, data):
        if len(self.datas) < 2:
            return self.warn("Can't delete last row")

        index = self.datas.index(data)
        self.datas.pop(index)

        for widget in data.widgets:
            self.grid.removeWidget(widget)
            widget.deleteLater()

        if self.props_editor.dataobj is data:
            self.props_editor.close()

        self.set_layout()
        self.draw()
        self.datas[index - 1].menu.setFocus()
        self.datas[index - 1].menu.lineEdit().selectAll()

    def get_scale(self, textbox, completer):
        completer.close_popup()
        text = text_type(textbox.text())
        try:
            return eval(text, CONSTANTS.copy())
        except Exception as e:
            self.warnings.append('Error setting scale: ' + text_type(e))
            return 1.0

    def get_key(self, menu):
        key = text_type(menu.itemText(menu.currentIndex()))
        text = text_type(menu.lineEdit().text())
        if key != text:
            self.warnings.append(
                'Plotted key (%s) does not match typed key (%s)' %
                (key, text))
        return key

    @staticmethod
    def cla(axes):
        tight, xmargin, ymargin = axes._tight, axes._xmargin, axes._ymargin
        axes.clear()
        axes._tight, axes._xmargin, axes._ymargin = tight, xmargin, ymargin

    def clear_pickers(self):
        if self.pickers is not None:
            [p.disable() for p in self.pickers]
            self.pickers = None

    def plot(self, axes, data, xname, xscale, yname, yscale, i, label):
        if xname in data.obj:
            x = data.obj[xname][..., i] * xscale
        y = data.obj[yname][..., i] * yscale

        def plot(y):
            if xname in data.obj:
                return axes.plot(x, y, label=label)
            else:
                return axes.plot(y, label=label)

        try:
            lines = plot(y)
        except ValueError:
            lines = plot(y.T)

        if isinstance(i, slice):
            i = 0
        for line in lines:
            if hasattr(data, 'cdata'):
                line.set_color(data.cmap(data.norm(data.cdata[i])))
                self.handles[(label,)] = line
            elif 'color' not in data.props and 'linestyle' not in data.props:
                style, color = next(self.styles)
                line.set_color(color)
                line.set_linestyle(style)
                self.handles[(label, color, style)] = line
            elif 'color' not in data.props:
                line.set_color(color_cycle[i % len(color_cycle)])
                self.handles[
                    (label, line.get_color(), data.props['linestyle'])] = line
            else:
                self.handles[
                    (label,
                     data.props.get('color', line.get_color()),
                     data.props.get('linestyle', line.get_linestyle()))] = line
            for key, value in data.props.items():
                getattr(line, 'set_' + key, lambda _: None)(value)

        return len(lines)

    def draw(self):
        self.mpl_toolbar.home = self.draw
        twin = any(d.twin for d in self.datas)
        self.clear_pickers()
        self.fig.clear()
        self.axes = self.fig.add_subplot(111)

        color_data = next((d for d in self.datas if hasattr(d, 'cdata')), None)
        if color_data and not twin:
            self.mappable = mpl.cm.ScalarMappable(norm=color_data.norm,
                                                  cmap=color_data.cmap)
            self.mappable.set_array(color_data.cdata)
            self.colorbar = self.fig.colorbar(
                self.mappable, ax=self.axes, fraction=0.1, pad=0.02)
        elif twin:
            self.axes2 = self.axes.twinx()

        for ax in self.axes, self.axes2:
            ax._tight = bool(self.margins)
            if self.margins:
                ax.margins(self.margins)

        xlabel = []
        ylabel = []
        xlabel2 = []
        ylabel2 = []
        self.warnings = []
        self.handles = OrderedDict()
        self.styles = cycle(product(linestyle_cycle, color_cycle))
        for d in self.datas:
            if d.twin:
                axes, x, y = self.axes2, xlabel2, ylabel2
            else:
                axes, x, y = self.axes, xlabel, ylabel
            scale = self.get_scale(d.scale_box, d.scale_compl)
            xscale = self.get_scale(d.xscale_box, d.xscale_compl)
            text = self.get_key(d.menu)
            xtext = self.get_key(d.xmenu)
            args = axes, d, xtext, xscale, text, scale
            if isiterable(d.labels):
                for i, label in enumerate(d.labels):
                    self.plot(*args + (i, label))
            else:
                n = self.plot(*args + (slice(None), d.labels))
                if n > 1:
                    d.labels = ['%s %d' % (d.labels, i) for i in range(n)]
                    return self.draw()
            axes.set_xlabel('')
            if xtext:
                x.append(xtext + ' (' + d.name + ')')
            y.append(text + ' (' + d.name + ')')

        self.axes.set_xlabel('\n'.join(xlabel))
        self.axes.set_ylabel('\n'.join(ylabel))
        self.draw_warnings()

        self.axes2.set_xlabel('\n'.join(xlabel2))
        self.axes2.set_ylabel('\n'.join(ylabel2))

        self.axes.set_xlim(self.xlim)
        self.axes.set_ylim(self.ylim)
        self.axes.set_xscale(self.xlogscale)
        self.axes.set_yscale(self.ylogscale)

        for ax in self.axes, self.axes2:
            ax.set_aspect('equal' if self.axisequal else 'auto', 'box-forced')
        legend = self.axes.legend(self.handles.values(),
                                  [k[0] for k in self.handles.keys()])
        legend.draggable(True)
        self.pickers = [picker(ax) for ax in [self.axes, self.axes2]]

        self.canvas.draw()

    def draw_warnings(self):
        self.axes.text(0.05, 0.05, '\n'.join(self.warnings),
                       transform=self.axes.transAxes, color='red')

    def canvas_key_press(self, event):
        key_press_handler(event, self.canvas, self.mpl_toolbar)
        if event.key == 'ctrl+q':
            self._close()
        elif event.key in mpl.rcParams['keymap.home']:
            self.xlim = self.ylim = None
            self.draw()
        elif event.key == 'ctrl+x':
            self.set_xlim(draw=False)
        elif event.key == 'ctrl+y':
            self.set_ylim(draw=False)
        elif event.key == 'ctrl+l':
            self.draw()
        self.xlogscale = self.axes.get_xscale()
        self.ylogscale = self.axes.get_yscale()

    def edit_parameters(self):
        xlim = self.axes.get_xlim()
        ylim = self.axes.get_ylim()
        self.mpl_toolbar.edit_parameters()
        if xlim != self.axes.get_xlim():
            self.xlim = self.axes.get_xlim()
        if ylim != self.axes.get_ylim():
            self.ylim = self.axes.get_ylim()
        self.xlogscale = self.axes.get_xscale()
        self.ylogscale = self.axes.get_yscale()

    def _margins(self):
        self.margins = 0 if self.margins else 0.05
        self.draw()

    def _options(self):
        self.edit_parameters()

    def _close(self):
        self.app.references.discard(self)
        self.window().close()

    def _input_lim(self, axis, default):
        default = text_type(default)
        if re.match(r'^\(.*\)$', default) or re.match(r'^\[.*\]$', default):
            default = default[1:-1]
        text, ok = QtGui.QInputDialog.getText(
            self, 'Set axis limits', '{} limits:'.format(axis),
            QtGui.QLineEdit.Normal, default)
        if ok:
            try:
                return eval(text_type(text), CONSTANTS.copy())
            except Exception:
                return None
        else:
            return None

    def set_xlim(self, draw=True):
        self.xlim = self._input_lim(
            'x', self.xlim or self.axes.get_xlim())
        if draw:
            self.draw()

    def set_ylim(self, draw=True):
        self.ylim = self._input_lim(
            'y', self.ylim or self.axes.get_ylim())
        if draw:
            self.draw()

    control_actions = {
        QtCore.Qt.Key_M: _margins,
        QtCore.Qt.Key_O: _options,
        QtCore.Qt.Key_Q: _close,
    }

    @staticmethod
    def data_dict(d):
        kwargs = OrderedDict((
            ('name', d.name),
            ('xname', text_type(d.xmenu.lineEdit().text())),
            ('xscale', text_type(d.xscale_box.text())),
            ('yname', text_type(d.menu.lineEdit().text())),
            ('yscale', text_type(d.scale_box.text())),
            ('props', d.props),
            ('labels', d.labels),
        ))
        for key in 'xscale', 'yscale':
            try:
                kwargs[key] = ast.literal_eval(kwargs[key])
            except ValueError:
                pass
            else:
                if float(kwargs[key]) == 1.0:
                    del kwargs[key]
        if not kwargs['props']:
            del kwargs['props']
        return kwargs

    def data_dicts(self):
        return "\n".join(text_type(self.dict_repr(self.data_dict(d)))
                         for d in self.datas)

    @classmethod
    def dict_repr(cls, d, top=True):
        if isinstance(d, dict):
            return ('{}' if top else 'dict({})').format(', '.join(
                ['{}={}'.format(k, cls.dict_repr(v, False))
                 for k, v in d.items()]))
        elif isinstance(d, string_types):
            return repr(str(d))
        return repr(d)

    def event(self, event):
        if (event.type() == QtCore.QEvent.KeyPress and
            event.modifiers() & CONTROL_MODIFIER and
                event.key() in self.control_actions):
            self.control_actions[event.key()](self)
            return True

        # Create duplicate of entire GUI with Ctrl+Shift+N
        elif (event.type() == QtCore.QEvent.KeyPress and
              event.modifiers() & CONTROL_MODIFIER and
              event.modifiers() & QtCore.Qt.ShiftModifier and
              event.key() == QtCore.Qt.Key_N):
            create(*[[d.obj, d.name, self.data_dict(d)] for d in self.datas])
            return True

        # Print dictionaries of keys and scales for all data with Ctrl+Shift+P
        elif (event.type() == QtCore.QEvent.KeyPress and
              event.modifiers() & CONTROL_MODIFIER and
              event.modifiers() & QtCore.Qt.ShiftModifier and
              event.key() == QtCore.Qt.Key_P):
            print(self.data_dicts())
            sys.stdout.flush()
            return True
        return super(Interact, self).event(event)
Exemple #48
0
class LabRADPlotWidget2(Qt.QWidget):

    def __init__(self, parent, cxn=None, path=[], dataset=None, toolbar=True, timer=None, settings={}):
        """
        A Qt widget that plots a labrad dataset, using Matplotlib.
        """
        # run qwidget init
        Qt.QWidget.__init__(self, parent)
        # create the qt basics
        self.figure = Figure()
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setSizePolicy(Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Expanding)
        if toolbar:
            self.toolbar = NavigationToolbar(self.canvas, None)
        else:
            self.toolbar = None
        self.layout = Qt.QVBoxLayout()
        self.layout.addWidget(self.canvas)
        if self.toolbar:
            self.layout.addWidget(self.toolbar)
        self.setLayout(self.layout)
        self.groupBoxLayout = Qt.QHBoxLayout()
        self.layout.addLayout(self.groupBoxLayout)
        self.makeOptionsBox()
        self.groupBoxes = []
        self.settings = settings
        # matplotlib variables
        self.rebuildPlot = False
        self.subplots = []
        self.lines = []
        # labrad variables
        self.path = path
        self.dataset = dataset
        # start the labrad connection
        if cxn is None:
            import labrad
            cxnDef = labrad.connectAsync(name=labrad.util.getNodeName() + ' Plot Widget')
            cxnDef.addCallback(self.setCxn)
            self.cxn = None
        else:
            self.setCxn(cxn)
        # give us a timer
        if timer is None:
            self.updateTimer = Qt.QTimer()
            self.updateTimer.timeout.connect(self.timerFunc)
            self.waitingOnLabrad=True
            self.updateTimer.start(UPDATE_PERIOD * 1000)
        else:
            self.updateTimer = timer
            self.updateTimer.timeout.connect(self.timerFunc)
            self.waitinOnLabrad=True
        
    def makeOptionsBox(self):
        vl = Qt.QVBoxLayout()
        self.rescaleCB = Qt.QCheckBox("Autoscale Y-Axis")
        self.rescaleCB.setChecked(True)
        
        vl.addWidget(self.rescaleCB)
        self.rescaleXCB = Qt.QCheckBox("Autoscale X-Axis")
        self.rescaleXCB.setChecked(True)
        
        vl.addWidget(self.rescaleXCB)
        l = Qt.QLabel("Minutes to Display")
        self.minutesToDisplayEdit = Qt.QLineEdit()
        hl = Qt.QHBoxLayout()
        hl.addWidget(l); hl.addWidget(self.minutesToDisplayEdit); vl.addLayout(hl)
        
        self.tempUnitsCB = Qt.QCheckBox("Temperature in F")
        self.tempUnitsCB.setChecked(False)
        vl.addWidget(self.tempUnitsCB)

        self.hideUncheckedCB = Qt.QCheckBox("Hide unchecked")
        self.hideUncheckedCB.setChecked(False)
        self.hideUncheckedCB.toggled.connect(self.hideUncheckedCallback)
        vl.addWidget(self.hideUncheckedCB)
        
        optGB = Qt.QGroupBox("Options")
        optGB.setCheckable(False)
        optGB.setLayout(vl)
        optGB.setSizePolicy(Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed)
        self.groupBoxLayout.addWidget(optGB, 0, QtCore.Qt.AlignTop)

    def hideUncheckedCallback(self, toggled):
        if toggled:
            for cb in self.checkBoxes:
                if not cb.isChecked():
                    cb.setVisible(False)
        else:
            for cb in self.checkBoxes:
                cb.setVisible(True)
        
    def setCxn(self, cxn):
        self.cxn = cxn
        if self.dataset:
            self.loadDataset()
        self.waitingOnLabrad=False
        
    def setDataset(self, path=[], dataset=None):
        if path:
            self.path = path
        if dataset:
            self.dataset = dataset
        self.loadDataset()
        
    def getDataset(self):
        return self.dataset
        
    def loadDataset(self):
        p = self.cxn.data_vault.packet()
        p.cd(self.path)
        p.dir()
        d = p.send()
        d.addCallback(self.loadDatasetCallback)
        
    def loadDatasetCallback(self, response):
        dsList = response.dir[1]
        if type(self.dataset) == str and not self.dataset in dsList:
            for ds in dsList:
                if self.dataset in ds:
                    self.dataset = ds
                    break
            else:   # note this else is for the for loop, not the if statement
                self.dataset = None
                print "Dataset %s not found!" % self.dataset
        p = self.cxn.data_vault.packet()
        p.open(self.dataset)
        p.send()
        self.rebuildPlot = True
        
    def timerFunc(self):
        if self.waitingOnLabrad:
            return
        if not self.dataset:
            return
        p = self.cxn.data_vault.packet()
        if self.rebuildPlot:
            p.variables()
        p.get(1000)
        d = p.send()
        d.addCallback(self.datavaultCallback)
        
    def datavaultCallback(self, response):
        if self.rebuildPlot and 'variables' not in response.settings:
            return
        elif self.rebuildPlot:
            for plot in self.subplots:
                self.figure.delaxes(plot)
            self.plots = []
            self.lines = []
            # list of legends
            self.plotLegends = list(set([x[0] for x in response.variables[1]]))
            # dict of lists of labels, where plotLabels[legend] = [list of labels for this legend]
            self.plotLabels = dict(zip(self.plotLegends, [[] for i in range(len(self.plotLegends))]))
            # dict of lists of units, as above
            self.plotUnits = dict(zip(self.plotLegends, [[] for i in range(len(self.plotLegends))]))
            # dict of lists of indices
            self.plotIndices = dict(zip(self.plotLegends, [[] for i in range(len(self.plotLegends))]))
            i = 0
            for legend, label, unit in response.variables[1]:
                i += 1
                self.plotLabels[legend].append(label)
                self.plotUnits[legend].append(unit)
                self.plotIndices[legend].append(i)
            # list of plots
            for i in range(len(self.plotLegends)):
                if i == 0:
                    self.plots.append(self.figure.add_subplot(len(self.plotLegends), 1, i))
                else:
                    self.plots.append(self.figure.add_subplot(len(self.plotLegends), 1, i, sharex=self.plots[0]))
                self.plots[i].set_ylabel(self.plotLegends[i])
                plt.setp(self.plots[i].get_xticklabels(), visible=False)
            self.plotData = response.get
            if 'xAxisIsTime' in self.settings.keys() and self.settings['xAxisIsTime']:
                self.plotT0 = self.plotData[0,0]
                self.plotData[:,0] -= self.plotT0
                self.plotData[:,0] /= 60.0
                self.xlabel = "Time [min] since %s" % time.strftime('%Y-%b-%d %H:%M', time.localtime(self.plotT0))
            else:
                self.xlabel = '%s [%s]' % response.variables[0][0]
            # create the lines
            for i in range(1, self.plotData.shape[1]):
                plotNum = self.plotLegends.index(response.variables[1][i-1][0])
                self.lines.append(self.plots[plotNum].add_line(mp.lines.Line2D(self.plotData[:,0], self.plotData[:,i],
                        label='%s [%s]' % response.variables[1][i-1][1:], color = COLORS[(i-1) % len(COLORS)],
                        marker='o', linestyle='-')))
            for plot in self.plots:
                #plot.legend(prop={'size': 'x-small'}, loc='upper left')
                plot.autoscale()
            self.plots[-1].set_xlabel(self.xlabel)
            self.buildGroupBoxes()
            self.canvas.draw()
            self.rebuildPlot = False
            self.applySettings()
        else:
            newdata = response.get
            if newdata.shape[1] == 0:
                return
            if 'xAxisIsTime' in self.settings.keys() and self.settings['xAxisIsTime']:
                newdata[:,0] -= self.plotT0
                newdata[:,0] /= 60.0
            self.plotData = np.append(self.plotData, newdata, axis=0)
            # trim down to appropriate size
            if self.plotData.shape[0] > MAX_POINTS:
                self.plotData = self.plotData[(self.plotData.shape[0] - MAX_POINTS):, :]
            for i in range(1, newdata.shape[1]):
                line = self.lines[i-1]
                if self.tempUnitsCB.isChecked() and '[K]' in line.get_label():
                    line.set_data(self.plotData[:,0], (self.plotData[:,i]-273.15)*1.8 + 32)
                elif self.tempUnitsCB.isChecked() and '[C]' in line.get_label():
                    line.set_data(self.plotData[:,0], self.plotData[:,i]*1.8 + 32)
                else:
                    line.set_data(self.plotData[:,0], self.plotData[:,i])
            self.scalePlots()
            self.canvas.draw()

    def scalePlots(self):
        ''' scale the plots to show all the data. only use visible lines. account for absolute limits in settings. '''
        for plot, legend in zip(self.plots, self.plotLegends):
            # determine x max and min
            xmax, xmin = max(self.plotData[:,0]), min(self.plotData[:,0])
            if 'xlimits' in self.settings.keys():
                for leg, amin, amax in self.settings['xlimits']:
                    if legend in leg:
                        xmax = min(xmax, amax)
                        xmin = max(xmin, amin)
                        break
            try:
                m = float(str(self.minutesToDisplayEdit.text()))
                if m > 0:
                    xmin = max(xmin, xmax-m)
            except ValueError:
                pass
            # determine y max and min
            plotIndices = [x for x in self.plotIndices[legend] if self.lines[x-1].get_visible()]
            if not plotIndices:
                continue
            xinds = np.where(np.logical_and(self.plotData[:,0] >= xmin, self.plotData[:,0] <= xmax))[0]
            ymax, ymin = self.plotData[:,plotIndices][xinds].max(), self.plotData[:,plotIndices][xinds].min()
            #ymax, ymin = self.plotData[:,plotIndices].max(), self.plotData[:,plotIndices].min()
            yr = ymax-ymin
            ymax += yr*0.1
            ymin -= yr*0.1
            if 'ylimits' in self.settings.keys():
                for leg, amin, amax in self.settings['ylimits']:
                    if legend in leg:
                        ymax = min(ymax, amax)
                        ymin = max(ymin, amin)
                        break

            
            if self.rescaleXCB.isChecked():
                plot.set_xlim(xmax=xmax, xmin=xmin)
            if self.rescaleCB.isChecked():
                plot.set_ylim(ymax=ymax, ymin=ymin)
            
    def applySettings(self):
        ''' apply the plot settings in the settings dict.
        things like which plots are visible, axis limits, etc.'''
        if 'activeLines' in self.settings.keys():
            for cb in self.checkBoxes:
                cb.setChecked(False)
            for al in self.settings['activeLines']:
                for cb in self.checkBoxes:
                    if al.strip() == str(cb.text()).strip():
                        cb.setChecked(True)
        if 'activePlots' in self.settings.keys():
            for ap in self.settings['activePlots']:
                for gb in self.groupBoxes:
                    if ap in str(gb.title()):
                        gb.setChecked(True)
                    else:
                        gb.setChecked(False)
                    gb.leaveEvent(None)
            self.groupBoxCallback()
        self.hideUncheckedCB.setChecked(True)
        self.hideUncheckedCallback(True)
        #if 'ylimits' in self.settings.keys():
            #for name, lim in ylimits:
                
            
    def buildGroupBoxes(self):
        while True:
            it = self.groupBoxLayout.takeAt(1)
            if not it:
                break
            self.groupBoxLayout.removeItem(it)
        self.groupBoxes = []
        self.checkBoxes = []
        self.checkBoxesToLines = {}
        for legend in self.plotLegends:
            vl = Qt.QVBoxLayout()
            if len(self.plotLabels[legend]) == 1:
                gb = Qt.QGroupBox("%s (%s)" % (legend, self.plotLabels[legend][0]))
            else:
                gb = Qt.QGroupBox(legend)
                for label in self.plotLabels[legend]:
                    l = self.lines[self.plotIndices[legend][self.plotLabels[legend].index(label)] - 1]
                    cb = Qt.QCheckBox(label)
                    cb.setStyleSheet('QCheckBox {color: %s; font-weight: bold}' % l.get_color())
                    cb.setChecked(True)
                    cb.toggled.connect(self.checkBoxCallback)
                    vl.addWidget(cb)
                    self.checkBoxes.append(cb)
                    self.checkBoxesToLines[cb] = l
            gb.setCheckable(True)
            gb.setChecked(True)
            gb.setLayout(vl)
            gb.setSizePolicy(Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Fixed)
            gb.clicked.connect(self.groupBoxCallback)
            self.groupBoxes.append(gb)
            self.groupBoxLayout.addWidget(gb, 0, QtCore.Qt.AlignTop)
            gb.leaveEvent(None)
        self.groupBoxLayout.addStretch()
        
            
    def checkBoxCallback(self):
        for cb in self.checkBoxes:
            self.checkBoxesToLines[cb].set_visible(cb.isChecked())
        self.scalePlots()
        self.canvas.draw()
        
    def groupBoxCallback(self):
        # count up number of active graphs
        numActive = 0
        for gb in self.groupBoxes:
            if gb.isChecked():
                numActive += 1
        # activate/deactivate
        i = 0
        for gb, plot in zip(self.groupBoxes, self.plots):
            if gb.isChecked():
                i+=1
                plot.set_visible(True)
                plot.change_geometry(numActive, 1, i)
                if i == numActive:
                    plt.setp(plot.get_xticklabels(), visible=True)
                    plot.set_xlabel(self.xlabel)
                else:
                    plt.setp(plot.get_xticklabels(), visible=False)
                    plot.set_xlabel('')
            else:
                plot.set_visible(False)
        self.canvas.draw()
Exemple #49
0
class PyAbel:  #(tk.Tk):

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

    def initialize(self):
        self.fn = None
        self.old_fn = None
        self.old_method = None
        self.old_fi = None
        self.AIM = None
        self.rmx = (368, 393)

        # matplotlib figure
        self.f = Figure(figsize=(2, 4))
        self.gs = gridspec.GridSpec(2, 2, width_ratios=[1, 2])
        self.gs.update(wspace=0.2, hspace=0.5)

        self.plt = []
        self.plt.append(self.f.add_subplot(self.gs[0]))
        self.plt.append(self.f.add_subplot(self.gs[1]))
        self.plt.append(self.f.add_subplot(self.gs[2], sharex=self.plt[0],
                        sharey=self.plt[0]))
        self.plt.append(self.f.add_subplot(self.gs[3]))
        for i in [0, 2]:
            self.plt[i].set_adjustable('box-forced')

        # hide until have data
        for i in range(4):
            self.plt[i].axis("off")

        # tkinter 
        # set default font size for buttons
        self.font = tkFont.Font(size=11)
        self.fontB = tkFont.Font(size=12, weight='bold')

        #frames top (buttons), text, matplotlib (canvas)
        self.main_container = tk.Frame(self.parent, height=10, width=100)
        self.main_container.pack(side="top", fill="both", expand=True)

        self.button_frame = tk.Frame(self.main_container)
        #self.info_frame = tk.Frame(self.main_container)
        self.matplotlib_frame = tk.Frame(self.main_container)

        self.button_frame.pack(side="top", fill="x", expand=True)
        #self.info_frame.pack(side="top", fill="x", expand=True)
        self.matplotlib_frame.pack(side="top", fill="both", expand=True)

        self._menus()
        self._button_area()
        self._plot_canvas()
        self._text_info_box()

    def _button_frame(self):
        self.button_frame = tk.Frame(self.main_container)
        self.button_frame.pack(side="top", fill="x", expand=True)
        self._menus()

    def _menus(self):
        # menus with callback ----------------
        # duplicates the button interface
        self.menubar = tk.Menu(self.parent)
        self.transform_method = tk.IntVar()

        # File - menu
        self.filemenu = tk.Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="Load image file",
                                  command=self._loadimage)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Exit", command=self._quit)
        self.menubar.add_cascade(label="File", menu=self.filemenu)

        # Process - menu
        self.processmenu = tk.Menu(self.menubar, tearoff=0)
        self.processmenu.add_command(label="Center image", command=self._center)
        self.submenu=tk.Menu(self.processmenu)
        for method in Abel_methods:
            self.submenu.add_radiobutton(label=method,
                 var=self.transform_method, val=Abel_methods.index(method),
                 command=self._transform)
        self.processmenu.add_cascade(label="Inverse Abel transform",
                 menu=self.submenu, underline=0)

        self.processmenu.add_command(label="Speed distribution",
                                     command=self._speed)
        self.processmenu.add_command(label="Angular distribution",
                                     command=self._anisotropy)
        self.angmenu=tk.Menu(self.processmenu)
        self.menubar.add_cascade(label="Processing", menu=self.processmenu)
    
        # view - menu
        self.viewmenu = tk.Menu(self.menubar, tearoff=0)
        self.viewmenu.add_command(label="Raw image", command=self._display)
        self.viewmenu.add_command(label="Inverse Abel transformed image",
                                  command=self._transform)
        self.viewmenu.add_command(label="view buttons",
                                  command=self._on_buttons)
        self.menubar.add_cascade(label="View", menu=self.viewmenu)


    def _button_area(self):
        # grid layout  
        # make expandable
        for col in range(5):
            self.button_frame.columnconfigure(col, weight=1)
            self.button_frame.rowconfigure(col, weight=1)

        # column 0 ---------
        # load image file button
        self.load = tk.Button(master=self.button_frame, text="load image",
                              font=self.fontB,
                              command=self._loadimage)
        self.load.grid(row=0, column=0, sticky=tk.W, padx=(5, 10), pady=(5, 0))
        self.sample_image = ttk.Combobox(master=self.button_frame,
                         font=self.font,
                         values=["from file", "from transform", "sample dribinski", "sample Ominus"],
                         width=14, height=4)
        self.sample_image.current(0)
        self.sample_image.grid(row=1, column=0, padx=(5, 10))

        # quit
        self.quit = tk.Button(master=self.button_frame, text="quit",
                              font=self.fontB,
                              command=self._quit)
        self.quit.grid(row=3, column=0, sticky=tk.W, padx=(5, 10), pady=(0, 5))
   
        # column 1 -----------
        # center image
        self.center = tk.Button(master=self.button_frame, text="center image",
                                anchor=tk.W, 
                                font=self.fontB,
                                command=self._center)
        self.center.grid(row=0, column=1, padx=(0, 20), pady=(5, 0))
        self.center_method = ttk.Combobox(master=self.button_frame,
                         font=self.font,
                         values=["com", "slice", "gaussian", "image_center"],
                         width=10, height=4)
        self.center_method.current(1)
        self.center_method.grid(row=1, column=1, padx=(0, 20))

        # column 2 -----------
        # Abel transform image
        self.recond = tk.Button(master=self.button_frame,
                                text="Abel transform image",
                                font=self.fontB,
                                command=self._transform)
        self.recond.grid(row=0, column=2, padx=(0, 10), pady=(5, 0))

        self.transform = ttk.Combobox(master=self.button_frame,
                         values=Abel_methods,
                         font=self.font,
                         width=10, height=len(Abel_methods))
        self.transform.current(2)
        self.transform.grid(row=1, column=2, padx=(0, 20))

        self.direction = ttk.Combobox(master=self.button_frame,
                         values=["inverse", "forward"],
                         font=self.font,
                         width=8, height=2)
        self.direction.current(0)
        self.direction.grid(row=2, column=2, padx=(0, 20))


        # column 3 -----------
        # speed button
        self.speed = tk.Button(master=self.button_frame, text="speed",
                               font=self.fontB,
                               command=self._speed)
        self.speed.grid(row=0, column=5, padx=20, pady=(5, 0))
        
        self.speedclr = tk.Button(master=self.button_frame, text="clear plot",
                                  font=self.font, command=self._speed_clr)
        self.speedclr.grid(row=1, column=5, padx=20)

        # column 4 -----------
        # anisotropy button
        self.aniso = tk.Button(master=self.button_frame, text="anisotropy",
                               font=self.fontB,
                               command=self._anisotropy)
        self.aniso.grid(row=0, column=6, pady=(5, 0))

        self.subframe = tk.Frame(self.button_frame)
        self.subframe.grid(row=1, column=6)
        self.rmin = tk.Entry(master=self.subframe, text='rmin', width=3,
                               font=self.font)
        self.rmin.grid(row=0, column=0)
        self.rmin.delete(0, tk.END)
        self.rmin.insert(0, self.rmx[0])
        self.lbl = tk.Label(master=self.subframe, text="to", font=self.font)
        self.lbl.grid(row=0, column=1)
        self.rmax = tk.Entry(master=self.subframe, text='rmax', width=3,
                             font=self.font)
        self.rmax.grid(row=0, column=2)
        self.rmax.delete(0, tk.END)
        self.rmax.insert(0, self.rmx[1])


        # turn off button interface
        self.hide_buttons = tk.Button(master=self.button_frame,
                                      text="hide buttons",
                                      font=self.fontB,
                                      command=self._hide_buttons)
        self.hide_buttons.grid(row=3, column=6, sticky=tk.E, pady=(0, 20))

    def _text_info_box(self):
        # text info box ---------------------
        self.text = ScrolledText(master=self.button_frame, height=4, 
                            fg="mediumblue",
                            bd=1, relief=tk.SUNKEN)
        self.text.insert(tk.END, "Work in progress, some features may"
                         " be incomplete\n\n")
        self.text.insert(tk.END, "To start load an image data file using"
                         " 'load image' button (or file menu)\n")
        self.text.insert(tk.END, "e.g. data/O2-ANU1024.txt.bz2\n")
        self.text.grid(row=3, column=1, columnspan=3, padx=5)


    def _plot_canvas(self):
        # matplotlib canvas --------------------------
        self.canvas = FigureCanvasTkAgg(self.f, master=self.matplotlib_frame) 
        #self.cid = self.canvas.mpl_connect('button_press_event', self._onclick)

        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.parent)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(anchor=tk.W, side=tk.TOP, fill=tk.BOTH, expand=1)


    def _onclick(self,event):
        print('button={:d}, x={:f}, y={:f}, xdata={:f}, ydata={:f}'.format(
        event.button, event.x, event.y, event.xdata, event.ydata))


    # call back functions -----------------------
    def _display(self):
        if self.fn is None:
            self._loadimage()

        # display image
        self.plt[0].imshow(self.IM, vmin=0)
        #rows, cols = self.IM.shape
        #r2 = rows/2
        #c2 = cols/2
        #self.a.plot((r2, r2), (0, cols), 'r--', lw=0.1)
        #self.a.plot((0, rows), (c2, c2),'r--', lw=0.1)
        #self.f.colorbar(self.a.get_children()[2], ax=self.f.gca())
        self.plt[0].set_title("raw image", fontsize=10)
        self.canvas.show()


    def _loadimage(self):

        if self.fn is not None:
            # clear old plot
            for i in range(4):
                self._clr_plt(i)
                self.plt[i].axis("off")

        self.fn = self.sample_image.get()
        # update what is occurring text box
        self.text.insert(tk.END, "\nloading image file {:s}".format(self.fn))
        self.text.see(tk.END)
        self.canvas.show()

        if self.fn == "from file":
            self.fn = askopenfilename()
            # read image file
            if ".txt" in self.fn:
                self.IM = np.loadtxt(self.fn)
            else:
                self.IM = imread(self.fn)
        elif self.fn == "from transform":
            self.IM = self.AIM
            self.AIM = None
            for i in range(1,4):
                self._clr_plt(i)
                self.plt[i].axis("off")
            self.direction.current(0)
        else:
            self.fn = self.fn.split(' ')[-1]
            self.IM = abel.tools.analytical.sample_image(n=1001, name=self.fn)
            self.direction.current(1) # raw images require 'forward' transform
            self.text.insert(tk.END,"\nsample image: (1) Abel transform 'forward', ")
            self.text.insert(tk.END,"              (2) load 'from transform', ") 
            self.text.insert(tk.END,"              (3) Abel transform 'inverse', ")
            self.text.insert(tk.END,"              (4) Speed")
            self.text.see(tk.END)


        # if even size image, make odd
        if self.IM.shape[0] % 2 == 0:
            self.IM = shift(self.IM, (-0.5, -0.5))[:-1,:-1]
    
        self.old_method = None
        self.AIM = None
        self.action = "file"
        self.rmin.delete(0, tk.END)
        self.rmin.insert(0, self.rmx[0])
        self.rmax.delete(0, tk.END)
        self.rmax.insert(0, self.rmx[1])

        # show the image
        self._display()
    

    def _center(self):
        self.action = "center"

        center_method = self.center_method.get()
        # update information text box
        self.text.insert(tk.END, "\ncentering image using {:s}".\
                         format(center_method))
        self.canvas.show()
    
        # center image via chosen method
        self.IM = abel.tools.center.center_image(self.IM, method=center_method,
                                  odd_size=True)
        self.text.insert(tk.END, "\ncenter offset = {:}".format(self.offset))
        self.text.see(tk.END)
    
        self._display()
    
    
    def _transform(self):
        #self.method = Abel_methods[self.transform_method.get()]
        self.method = self.transform.get()
        self.fi = self.direction.get()
    
        if self.method != self.old_method or self.fi != self.old_fi:
            # Abel transform of whole image
            self.text.insert(tk.END,"\n{:s} {:s} Abel transform:".\
                             format(self.method, self.fi))
            if "basex" in self.method:
                self.text.insert(tk.END,
                              "\nbasex: first time calculation of the basis"
                              " functions may take a while ...")
            if "onion" in self.method:
               self.text.insert(tk.END,"\nonion_peeling: method is in early "
                              "testing and may not produce reliable results")
            if "direct" in self.method:
               self.text.insert(tk.END,"\ndirect: calculation is slowed if Cython"
                                       " unavailable ...")
            self.canvas.show()
    
            self.AIM = abel.transform(self.IM, method=self.method, 
                                      direction=self.fi,
                                      symmetry_axis=None)['transform']
            self.rmin.delete(0, tk.END)
            self.rmin.insert(0, self.rmx[0])
            self.rmax.delete(0, tk.END)
            self.rmax.insert(0, self.rmx[1])
    
        if self.old_method != self.method or self.fi != self.old_fi or\
           self.action not in ["speed", "anisotropy"]:
            self.plt[2].set_title(self.method+" {:s} Abel transform".format(self.fi),
                            fontsize=10)
            self.plt[2].imshow(self.AIM, vmin=0, vmax=self.AIM.max()/5.0)
            #self.f.colorbar(self.c.get_children()[2], ax=self.f.gca())
            #self.text.insert(tk.END, "{:s} inverse Abel transformed image".format(self.method))

        self.text.see(tk.END)
        self.old_method = self.method
        self.old_fi = self.fi
        self.canvas.show()
    
    def _speed(self):
        self.action = "speed"
        # inverse Abel transform
        self._transform()
        # update text box in case something breaks
        self.text.insert(tk.END, "\nspeed distribution")
        self.text.see(tk.END)
        self.canvas.show()
    
        # speed distribution
        self.radial, self.speed_dist = abel.tools.vmi.angular_integration(self.AIM)
    
        self.plt[1].axis("on")
        self.plt[1].plot(self.radial, self.speed_dist/self.speed_dist[10:].max(),
                         label=self.method)
        self.plt[1].axis(xmax=500, ymin=-0.05)
        self.plt[1].set_xlabel("radius (pixels)", fontsize=9)
        self.plt[1].set_ylabel("normalized intensity")
        self.plt[1].set_title("radial speed distribution", fontsize=12)
        self.plt[1].legend(fontsize=9)

        self.action = None
        self.canvas.show()

    def _speed_clr(self):
        self._clr_plt(1)

    def _clr_plt(self, i):
        self.f.delaxes(self.plt[i])
        self.plt[i] = self.f.add_subplot(self.gs[i]) 
        self.canvas.show()
    
    def _anisotropy(self):

        def P2(x):   # 2nd order Legendre polynomial
            return (3*x*x-1)/2
    
    
        def PAD(theta, beta, amp):
            return amp*(1 + beta*P2(np.cos(theta)))
    
        self.action = "anisotropy"
        self._transform()
        # radial range over which to follow the intensity variation with angle
        self.rmx = (int(self.rmin.get()), int(self.rmax.get()))
    
        self.text.insert(tk.END,"\nanisotropy parameter pixel range {:} to {:}: "\
                               .format(*self.rmx))
        self.canvas.show()
    
        # inverse Abel transform
        self._transform()
    
        # intensity vs angle
        self.intensity, self.theta = abel.tools.vmi.\
                                     calculate_angular_distributions(self.AIM,\
                                     radial_ranges=[self.rmx,])
    
        # fit to P2(cos theta)
        self.beta, self.amp = abel.tools.vmi.anisotropy_parameter(self.theta, self.intensity[0])
    
        self.text.insert(tk.END," beta = {:g}+-{:g}".format(*self.beta))
    
        self._clr_plt(3)
        self.plt[3].axis("on")
        
        self.plt[3].plot(self.theta, self.intensity[0], 'r-')
        self.plt[3].plot(self.theta, PAD(self.theta, self.beta[0], self.amp[0]), 'b-', lw=2)
        self.plt[3].annotate("$\\beta({:d},{:d})={:.2g}\pm{:.2g}$".format(*self.rmx+self.beta), (-np.pi/2,-2))
        self.plt[3].set_title("anisotropy", fontsize=12)
        self.plt[3].set_xlabel("angle", fontsize=9)
        self.plt[3].set_ylabel("intensity")

        self.action = None
        self.canvas.show()

    def _hide_buttons(self):
        self.button_frame.destroy()

    def _on_buttons(self):
        self._button_frame()
    
    def _quit(self):
        self.parent.quit()     # stops mainloop
        self.parent.destroy()  # this is necessary on Windows to prevent
Exemple #50
0
class TimelineFrame(wx.Frame):
    """The main frame of the application"""

    def __init__(self, parent):
        wx.Frame.__init__(
            self,
            parent,
            id=wx.ID_ANY,
            title=_("GRASS GIS Timeline Tool"))

        tgis.init(True)
        self.datasets = []
        self.timeData = {}
        self._layout()
        self.temporalType = None
        self.unit = None
        # We create a database interface here to speedup the GUI
        self.dbif = tgis.SQLDatabaseInterfaceConnection()
        self.dbif.connect()

    def __del__(self):
        """Close the database interface and stop the messenger and C-interface
           subprocesses.
        """
        if self.dbif.connected is True:
            self.dbif.close()
        tgis.stop_subprocesses()

    def _layout(self):
        """Creates the main panel with all the controls on it:
             * mpl canvas
             * mpl navigation toolbar
             * Control panel for interaction
        """
        self.panel = wx.Panel(self)

        # Create the mpl Figure and FigCanvas objects.
        # 5x4 inches, 100 dots-per-inch
        #
        # color =  wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
        self.fig = Figure((5.0, 4.0), facecolor=(1, 1, 1))
        self.canvas = FigCanvas(self.panel, wx.ID_ANY, self.fig)
        # axes are initialized later
        self.axes2d = None
        self.axes3d = None

        # Create the navigation toolbar, tied to the canvas
        #
        self.toolbar = NavigationToolbar(self.canvas)

        #
        # Layout
        #

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
        self.vbox.Add(self.toolbar, 0, wx.EXPAND)
        self.vbox.AddSpacer(10)

        gridSizer = wx.GridBagSizer(hgap=5, vgap=5)

        self.datasetSelect = gselect.Select(parent=self.panel, id=wx.ID_ANY,
                                            size=globalvar.DIALOG_GSELECT_SIZE,
                                            type='stds', multiple=True)
        self.drawButton = wx.Button(self.panel, id=wx.ID_ANY, label=_("Draw"))
        self.drawButton.Bind(wx.EVT_BUTTON, self.OnRedraw)
        self.helpButton = wx.Button(self.panel, id=wx.ID_ANY, label=_("Help"))
        self.helpButton.Bind(wx.EVT_BUTTON, self.OnHelp)
        self.view3dCheck = wx.CheckBox(
            self.panel, id=wx.ID_ANY,
            label=_("3D plot of spatio-temporal extents"))
        self.view3dCheck.Bind(wx.EVT_CHECKBOX, self.OnRedraw)
        if not check_version(1, 0, 0):
            self.view3dCheck.SetLabel(_("3D plot of spatio-temporal extents "
                                        "(matplotlib >= 1.0.0)"))
            self.view3dCheck.Disable()

        gridSizer.Add(wx.StaticText(self.panel, id=wx.ID_ANY,
                                    label=_("Select space time dataset(s):")),
                      pos=(0, 0), flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
        gridSizer.Add(self.datasetSelect, pos=(1, 0), flag=wx.EXPAND)
        gridSizer.Add(self.drawButton, pos=(1, 1), flag=wx.EXPAND)
        gridSizer.Add(self.helpButton, pos=(1, 2), flag=wx.EXPAND)
        gridSizer.Add(
            self.view3dCheck, pos=(2, 0),
            flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)

        self.vbox.Add(
            gridSizer,
            proportion=0,
            flag=wx.EXPAND | wx.ALL,
            border=10)

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

    def _getData(self, timeseries):
        """Load data and read properties"""
        self.timeData = {}
        mode = None
        unit = None

        for series in timeseries:
            name = series[0] + '@' + series[1]
            etype = series[2]
            sp = tgis.dataset_factory(etype, name)
            if not sp.is_in_db(dbif=self.dbif):
                GError(
                    self,
                    message=_("Dataset <%s> not found in temporal database") %
                    (name))
                return

            sp.select(dbif=self.dbif)

            self.timeData[name] = {}
            self.timeData[name]['elementType'] = series[2]
            self.timeData[name][
                'temporalType'] = sp.get_temporal_type()  # abs/rel

            if mode is None:
                mode = self.timeData[name]['temporalType']
            elif self.timeData[name]['temporalType'] != mode:
                GError(
                    parent=self, message=_(
                        "Datasets have different temporal type "
                        "(absolute x relative), which is not allowed."))
                return

            # check topology
            maps = sp.get_registered_maps_as_objects(dbif=self.dbif)
            self.timeData[name]['validTopology'] = sp.check_temporal_topology(
                maps=maps, dbif=self.dbif)

            self.timeData[name][
                'temporalMapType'] = sp.get_map_time()  # point/interval
            self.timeData[name]['unit'] = None  # only with relative
            if self.timeData[name]['temporalType'] == 'relative':
                start, end, self.timeData[name][
                    'unit'] = sp.get_relative_time()
                if unit is None:
                    unit = self.timeData[name]['unit']
                elif self.timeData[name]['unit'] != unit:
                    GError(
                        self, _("Datasets have different time unit which is not allowed."))
                    return

            self.timeData[name]['start_datetime'] = []
            # self.timeData[name]['start_plot'] = []
            self.timeData[name]['end_datetime'] = []
            # self.timeData[name]['end_plot'] = []
            self.timeData[name]['names'] = []
            self.timeData[name]['north'] = []
            self.timeData[name]['south'] = []
            self.timeData[name]['west'] = []
            self.timeData[name]['east'] = []

            columns = ','.join(['name', 'start_time', 'end_time',
                                'north', 'south', 'west', 'east'])

            rows = sp.get_registered_maps(columns=columns, where=None,
                                          order='start_time', dbif=self.dbif)
            if not rows:
                GError(
                    parent=self,
                    message=_("Dataset <{name}> is empty").format(
                        name=series[0] +
                        '@' +
                        series[1]))
                return
            for row in rows:
                mapName, start, end, north, south, west, east = row
                self.timeData[name]['start_datetime'].append(start)
                self.timeData[name]['end_datetime'].append(end)
                self.timeData[name]['names'].append(mapName)
                self.timeData[name]['north'].append(north)
                self.timeData[name]['south'].append(south)
                self.timeData[name]['west'].append(west)
                self.timeData[name]['east'].append(east)

        self.temporalType = mode
        self.unit = unit

    def _draw3dFigure(self):
        """Draws 3d view (spatio-temporal extents).


        Only for matplotlib versions >= 1.0.0.
        Earlier versions cannot draw time ticks and alpha
        and it has a slightly different API.
        """
        self.axes3d.clear()
        self.axes3d.grid(False)
        # self.axes3d.grid(True)
        if self.temporalType == 'absolute':
            convert = mdates.date2num
        else:
            convert = lambda x: x

        colors = cycle(COLORS)
        plots = []
        for name in self.datasets:
            name = name[0] + '@' + name[1]
            startZ = convert(self.timeData[name]['start_datetime'])
            mapType = self.timeData[name]['temporalMapType']
            if mapType == 'interval':
                dZ = convert(self.timeData[name]['end_datetime']) - startZ

            else:
                dZ = [0] * len(startZ)

            startX = self.timeData[name]['west']
            dX = self.timeData[name]['east'] - np.array(startX)
            startY = self.timeData[name]['south']
            dY = self.timeData[name]['north'] - np.array(startY)

            color = colors.next()
            plots.append(self.axes3d.bar3d(startX, startY, startZ, dX, dY, dZ,
                                           color=color, alpha=ALPHA))

        params = grass.read_command('g.proj', flags='g')
        params = grass.parse_key_val(params)
        if 'unit' in params:
            self.axes3d.set_xlabel(_("X [%s]") % params['unit'])
            self.axes3d.set_ylabel(_("Y [%s]") % params['unit'])
        else:
            self.axes3d.set_xlabel(_("X"))
            self.axes3d.set_ylabel(_("Y"))

        if self.temporalType == 'absolute':
            if check_version(1, 1, 0):
                self.axes3d.zaxis_date()
        self.axes3d.set_zlabel(_('Time'))
        self.axes3d.mouse_init()
        self.canvas.draw()

    def _draw2dFigure(self):
        """Draws 2D plot (temporal extents)"""
        self.axes2d.clear()
        self.axes2d.grid(True)
        if self.temporalType == 'absolute':
            convert = mdates.date2num
        else:
            convert = lambda x: x

        colors = cycle(COLORS)

        yticksNames = []
        yticksPos = []
        plots = []
        lookUp = LookUp(self.timeData)
        for i, name in enumerate(self.datasets):
            # just name; with mapset it would be long
            yticksNames.append(name[0])
            name = name[0] + '@' + name[1]
            yticksPos.append(i)
            barData = []
            pointData = []
            mapType = self.timeData[name]['temporalMapType']

            start = convert(self.timeData[name]['start_datetime'])
            # TODO: mixed
            if mapType == 'interval':
                end = convert(self.timeData[name]['end_datetime'])
                lookUpData = zip(start, end)
                duration = end - np.array(start)
                barData = zip(start, duration)
                lookUp.AddDataset(type_='bar', yrange=(i - 0.1, i + 0.1),
                                  xranges=lookUpData, datasetName=name)

            else:
                # self.timeData[name]['end_plot'] = None
                pointData = start
                lookUp.AddDataset(
                    type_='point',
                    yrange=i,
                    xranges=pointData,
                    datasetName=name)
            color = colors.next()
            if mapType == 'interval':
                plots.append(
                    self.axes2d.broken_barh(
                        xranges=barData,
                        yrange=(
                            i - 0.1,
                            0.2),
                        facecolors=color,
                        alpha=ALPHA))
            else:
                plots.append(
                    self.axes2d.plot(
                        pointData,
                        [i] * len(pointData),
                        marker='o',
                        linestyle='None',
                        color=color)[0])

        if self.temporalType == 'absolute':
            self.axes2d.xaxis_date()
            self.fig.autofmt_xdate()
            # self.axes2d.set_xlabel(_("Time"))
        else:
            self.axes2d.set_xlabel(_("Time [%s]") % self.unit)

        self.axes2d.set_yticks(yticksPos)
        self.axes2d.set_yticklabels(yticksNames)
        self.axes2d.set_ylim(min(yticksPos) - 1, max(yticksPos) + 1)

        # adjust xlim
        xlim = self.axes2d.get_xlim()
        padding = ceil((xlim[1] - xlim[0]) / 20.)
        self.axes2d.set_xlim(xlim[0] - padding, xlim[1] + padding)

        self.canvas.draw()
        DataCursor(plots, lookUp, InfoFormat)

    def OnRedraw(self, event):
        """Required redrawing."""
        datasets = self.datasetSelect.GetValue().strip()
        if not datasets:
            return
        datasets = datasets.split(',')
        try:
            datasets = self._checkDatasets(datasets)
            if not datasets:
                return
        except GException as e:
            GError(parent=self, message=unicode(e), showTraceback=False)
            return

        self.datasets = datasets
        self._redraw()

    def _redraw(self):
        """Readraw data.

        Decides if to draw also 3D and adjusts layout if needed.
        """
        self._getData(self.datasets)

        # axes3d are physically removed
        if not self.axes2d:
            self.axes2d = self.fig.add_subplot(1, 1, 1)
        self._draw2dFigure()
        if check_version(1, 0, 0):
            if self.view3dCheck.IsChecked():
                self.axes2d.change_geometry(2, 1, 1)
                if not self.axes3d:
                    # do not remove this import - unused but it is required for
                    # 3D
                    from mpl_toolkits.mplot3d import Axes3D  # pylint: disable=W0611
                    self.axes3d = self.fig.add_subplot(
                        2, 1, 2, projection='3d')

                self.axes3d.set_visible(True)
                self._draw3dFigure()
            else:
                if self.axes3d:
                    self.fig.delaxes(self.axes3d)
                    self.axes3d = None
                self.axes2d.change_geometry(1, 1, 1)
                self.canvas.draw()

    def _checkDatasets(self, datasets):
        """Checks and validates datasets.

        Reports also type of dataset (e.g. 'strds').

        :return: (mapName, mapset, type)
        """
        validated = []
        tDict = tgis.tlist_grouped('stds', group_type=True, dbif=self.dbif)
        # nested list with '(map, mapset, etype)' items
        allDatasets = [[[(map, mapset, etype) for map in maps]
                        for etype, maps in etypesDict.iteritems()]
                       for mapset, etypesDict in tDict.iteritems()]
        # flatten this list
        if allDatasets:
            allDatasets = reduce(
                lambda x,
                y: x + y,
                reduce(
                    lambda x,
                    y: x + y,
                    allDatasets))
            mapsets = tgis.get_tgis_c_library_interface().available_mapsets()
            allDatasets = [
                i
                for i in sorted(
                    allDatasets, key=lambda l: mapsets.index(l[1]))]

        for dataset in datasets:
            errorMsg = _("Space time dataset <%s> not found.") % dataset
            if dataset.find("@") >= 0:
                nameShort, mapset = dataset.split('@', 1)
                indices = [n for n, (mapName, mapsetName, etype) in enumerate(
                    allDatasets) if nameShort == mapName and mapsetName == mapset]
            else:
                indices = [n for n, (mapName, mapset, etype) in enumerate(
                    allDatasets) if dataset == mapName]

            if len(indices) == 0:
                raise GException(errorMsg)
            elif len(indices) >= 2:
                dlg = wx.SingleChoiceDialog(
                    self,
                    message=_(
                        "Please specify the space time dataset <%s>." %
                        dataset),
                    caption=_("Ambiguous dataset name"),
                    choices=[("%(map)s@%(mapset)s: %(etype)s" %
                              {'map': allDatasets[i][0],
                               'mapset': allDatasets[i][1],
                               'etype': allDatasets[i][2]}) for i in indices],
                    style=wx.CHOICEDLG_STYLE | wx.OK)
                if dlg.ShowModal() == wx.ID_OK:
                    index = dlg.GetSelection()
                    validated.append(allDatasets[indices[index]])
                else:
                    continue
            else:
                validated.append(allDatasets[indices[0]])

        return validated

    def OnHelp(self, event):
        RunCommand('g.manual', quiet=True, entry='g.gui.timeline')

#  interface

    def SetDatasets(self, datasets):
        """Set data"""
        if not datasets:
            return
        try:
            datasets = self._checkDatasets(datasets)
            if not datasets:
                return
        except GException as e:
            GError(parent=self, message=unicode(e), showTraceback=False)
            return
        self.datasets = datasets
        self.datasetSelect.SetValue(
            ','.join(map(lambda x: x[0] + '@' + x[1], datasets)))
        self._redraw()

    def Show3D(self, show):
        """Show also 3D if possible"""
        if check_version(1, 0, 0):
            self.view3dCheck.SetValue(show)
Exemple #51
0
class MainFrame(wx.Frame):
    """Contains the main GUI and button boxes"""
    def __init__(self, parent, config, video, shuffle, Dataframe, scorer,
                 savelabeled):
        # Settting the GUI size and panels design
        displays = (wx.Display(i) for i in range(wx.Display.GetCount())
                    )  # Gets the number of displays
        screenSizes = [
            display.GetGeometry().GetSize() for display in displays
        ]  # Gets the size of each display
        index = 0  # For display 1.
        screenWidth = screenSizes[index][0]
        screenHeight = screenSizes[index][1]
        self.gui_size = (screenWidth * 0.7, screenHeight * 0.85)

        wx.Frame.__init__(
            self,
            parent,
            id=wx.ID_ANY,
            title='DeepLabCut2.0 - Manual Outlier Frame Extraction',
            size=wx.Size(self.gui_size),
            pos=wx.DefaultPosition,
            style=wx.RESIZE_BORDER | wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetStatusText("")

        self.SetSizeHints(
            wx.Size(self.gui_size)
        )  #  This sets the minimum size of the GUI. It can scale now!

        ###################################################################################################################################################
        # Spliting the frame into top and bottom panels. Bottom panels contains the widgets. The top panel is for showing images and plotting!
        topSplitter = wx.SplitterWindow(self)

        self.image_panel = ImagePanel(topSplitter, config, video, shuffle,
                                      Dataframe, self.gui_size)
        self.widget_panel = WidgetPanel(topSplitter)

        topSplitter.SplitHorizontally(self.image_panel,
                                      self.widget_panel,
                                      sashPosition=self.gui_size[1] *
                                      0.83)  #0.9
        topSplitter.SetSashGravity(1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(topSplitter, 1, wx.EXPAND)
        self.SetSizer(sizer)

        ###################################################################################################################################################
        # Add Buttons to the WidgetPanel and bind them to their respective functions.

        widgetsizer = wx.WrapSizer(orient=wx.HORIZONTAL)

        self.load_button_sizer = wx.BoxSizer(wx.VERTICAL)
        self.help_button_sizer = wx.BoxSizer(wx.VERTICAL)

        self.help = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Help")
        self.help_button_sizer.Add(self.help, 1, wx.ALL, 15)
        #        widgetsizer.Add(self.help , 1, wx.ALL, 15)
        self.help.Bind(wx.EVT_BUTTON, self.helpButton)

        widgetsizer.Add(self.help_button_sizer, 1, wx.ALL, 0)

        self.grab = wx.Button(self.widget_panel,
                              id=wx.ID_ANY,
                              label="Grab Frames")
        widgetsizer.Add(self.grab, 1, wx.ALL, 15)
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.grab.Enable(True)

        widgetsizer.AddStretchSpacer(5)
        self.slider = wx.Slider(self.widget_panel,
                                id=wx.ID_ANY,
                                value=0,
                                minValue=0,
                                maxValue=1,
                                size=(200, -1),
                                style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS
                                | wx.SL_LABELS)
        widgetsizer.Add(self.slider, 1, wx.ALL, 5)
        self.slider.Bind(wx.EVT_SLIDER, self.OnSliderScroll)

        widgetsizer.AddStretchSpacer(5)
        self.start_frames_sizer = wx.BoxSizer(wx.VERTICAL)
        self.end_frames_sizer = wx.BoxSizer(wx.VERTICAL)

        self.start_frames_sizer.AddSpacer(15)
        #        self.startFrame = wx.SpinCtrl(self.widget_panel, value='0', size=(100, -1), min=0, max=120)
        self.startFrame = wx.SpinCtrl(self.widget_panel,
                                      value='0',
                                      size=(100, -1))  #,style=wx.SP_VERTICAL)
        self.startFrame.Enable(False)
        self.start_frames_sizer.Add(self.startFrame, 1,
                                    wx.EXPAND | wx.ALIGN_LEFT, 15)
        start_text = wx.StaticText(self.widget_panel,
                                   label='Start Frame Index')
        self.start_frames_sizer.Add(start_text, 1, wx.EXPAND | wx.ALIGN_LEFT,
                                    15)
        self.checkBox = wx.CheckBox(self.widget_panel,
                                    id=wx.ID_ANY,
                                    label='Range of frames')
        self.checkBox.Bind(wx.EVT_CHECKBOX, self.activate_frame_range)
        self.start_frames_sizer.Add(self.checkBox, 1,
                                    wx.EXPAND | wx.ALIGN_LEFT, 15)
        #
        self.end_frames_sizer.AddSpacer(15)
        self.endFrame = wx.SpinCtrl(self.widget_panel,
                                    value='1',
                                    size=(160, -1))  #, min=1, max=120)
        self.endFrame.Enable(False)
        self.end_frames_sizer.Add(self.endFrame, 1, wx.EXPAND | wx.ALIGN_LEFT,
                                  15)
        end_text = wx.StaticText(self.widget_panel, label='Number of Frames')
        self.end_frames_sizer.Add(end_text, 1, wx.EXPAND | wx.ALIGN_LEFT, 15)
        self.updateFrame = wx.Button(self.widget_panel,
                                     id=wx.ID_ANY,
                                     label="Update")
        self.end_frames_sizer.Add(self.updateFrame, 1,
                                  wx.EXPAND | wx.ALIGN_LEFT, 15)
        self.updateFrame.Bind(wx.EVT_BUTTON, self.updateSlider)
        self.updateFrame.Enable(False)

        widgetsizer.Add(self.start_frames_sizer, 1, wx.ALL, 0)
        widgetsizer.AddStretchSpacer(5)
        widgetsizer.Add(self.end_frames_sizer, 1, wx.ALL, 0)
        widgetsizer.AddStretchSpacer(15)

        self.quit = wx.Button(self.widget_panel, id=wx.ID_ANY, label="Quit")
        widgetsizer.Add(self.quit, 1, wx.ALL, 15)
        self.quit.Bind(wx.EVT_BUTTON, self.quitButton)
        self.quit.Enable(True)

        self.widget_panel.SetSizer(widgetsizer)
        self.widget_panel.SetSizerAndFit(widgetsizer)

        # Variables initialization
        self.numberFrames = 0
        self.currFrame = 0
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.drs = []
        self.extract_range_frame = False
        self.firstFrame = 0
        # self.cropping = False

        # Read confing file
        self.cfg = auxiliaryfunctions.read_config(config)
        self.Task = self.cfg['Task']
        self.start = self.cfg['start']
        self.stop = self.cfg['stop']
        self.date = self.cfg['date']
        self.trainFraction = self.cfg['TrainingFraction']
        self.trainFraction = self.trainFraction[0]
        self.videos = self.cfg['video_sets'].keys()
        self.bodyparts = self.cfg['bodyparts']
        self.colormap = plt.get_cmap(self.cfg['colormap'])
        self.colormap = self.colormap.reversed()
        self.markerSize = self.cfg['dotsize']
        self.alpha = self.cfg['alphavalue']
        self.iterationindex = self.cfg['iteration']
        self.cropping = self.cfg['cropping']
        self.video_names = [Path(i).stem for i in self.videos]
        self.config_path = Path(config)
        self.video_source = Path(video).resolve()
        self.shuffle = shuffle
        self.Dataframe = Dataframe
        self.scorer = scorer
        self.savelabeled = savelabeled

        # Read the video file
        self.vid = cv2.VideoCapture(str(self.video_source))
        self.videoPath = os.path.dirname(self.video_source)
        self.filename = Path(self.video_source).name
        self.numberFrames = int(self.vid.get(cv2.CAP_PROP_FRAME_COUNT))
        self.strwidth = int(np.ceil(np.log10(self.numberFrames)))
        # Set the values of slider and range of frames
        self.startFrame.SetMax(self.numberFrames - 1)
        self.slider.SetMax(self.numberFrames - 1)
        self.endFrame.SetMax(self.numberFrames - 1)
        self.startFrame.Bind(wx.EVT_SPINCTRL, self.updateSlider)  #wx.EVT_SPIN
        # Set the status bar
        self.statusbar.SetStatusText('Working on video: {}'.format(
            os.path.split(str(self.video_source))[-1]))
        # Adding the video file to the config file.
        if not (str(self.video_source.stem) in self.video_names):
            add.add_new_videos(self.config_path, [self.video_source])

        self.filename = Path(self.video_source).name
        self.update()
        self.plot_labels()
        self.widget_panel.Layout()

    def quitButton(self, event):
        """
        Quits the GUI
        """
        self.statusbar.SetStatusText("")
        dlg = wx.MessageDialog(None, "Are you sure?", "Quit!",
                               wx.YES_NO | wx.ICON_WARNING)
        result = dlg.ShowModal()
        if result == wx.ID_YES:
            print("Quitting for now!")
            self.Destroy()

    def updateSlider(self, event):
        self.slider.SetValue(self.startFrame.GetValue())
        self.startFrame.SetValue(self.slider.GetValue())
        self.axes.clear()
        self.figure.delaxes(self.figure.axes[1])
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.currFrame = (self.slider.GetValue())
        self.update()
        self.plot_labels()

    def activate_frame_range(self, event):
        """
        Activates the frame range boxes
        """
        self.checkSlider = event.GetEventObject()
        if self.checkSlider.GetValue() == True:
            self.extract_range_frame = True
            self.startFrame.Enable(True)
            self.startFrame.SetValue(self.slider.GetValue())
            self.endFrame.Enable(True)
            self.updateFrame.Enable(True)
            self.grab.Enable(False)
        else:
            self.extract_range_frame = False
            self.startFrame.Enable(False)
            self.endFrame.Enable(False)
            self.updateFrame.Enable(False)
            self.grab.Enable(True)

    def line_select_callback(self, eclick, erelease):
        'eclick and erelease are the press and release events'
        self.new_x1, self.new_y1 = eclick.xdata, eclick.ydata
        self.new_x2, self.new_y2 = erelease.xdata, erelease.ydata

    def OnSliderScroll(self, event):
        """
        Slider to scroll through the video
        """
        self.axes.clear()
        self.figure.delaxes(self.figure.axes[1])
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.currFrame = (self.slider.GetValue())
        self.startFrame.SetValue(self.currFrame)
        self.update()
        self.plot_labels()

    def update(self):
        """
        Updates the image with the current slider index
        """
        self.grab.Enable(True)
        self.grab.Bind(wx.EVT_BUTTON, self.grabFrame)
        self.figure, self.axes, self.canvas = self.image_panel.getfigure()
        self.vid.set(1, self.currFrame)
        ret, frame = self.vid.read()
        frame = img_as_ubyte(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
        if ret:
            if self.cropping:
                self.coords = (self.cfg['x1'], self.cfg['x2'], self.cfg['y1'],
                               self.cfg['y2'])
                frame = frame[int(self.coords[2]):int(self.coords[3]),
                              int(self.coords[0]):int(self.coords[1]), :]
            else:
                self.coords = None
            self.ax = self.axes.imshow(frame, cmap=self.colormap)
            self.axes.set_title(
                str(
                    str(self.currFrame) + "/" + str(self.numberFrames - 1) +
                    " " + self.filename))
            self.figure.canvas.draw()
        else:
            print("Invalid frame")

    def chooseFrame(self):
        ret, frame = self.vid.read()
        frame = img_as_ubyte(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
        if self.cropping:
            self.coords = (self.cfg['x1'], self.cfg['x2'], self.cfg['y1'],
                           self.cfg['y2'])
            frame = frame[int(self.coords[2]):int(self.coords[3]),
                          int(self.coords[0]):int(self.coords[1]), :]
        else:
            self.coords = None
        fname = Path(self.filename)
        output_path = self.config_path.parents[0] / 'labeled-data' / fname.stem

        self.machinefile = os.path.join(
            str(output_path),
            'machinelabels-iter' + str(self.iterationindex) + '.h5')
        name = str(fname.stem)
        DF = self.Dataframe.ix[[self.currFrame]]
        DF.index = [
            os.path.join('labeled-data', name,
                         "img" + str(index).zfill(self.strwidth) + ".png")
            for index in DF.index
        ]
        img_name = str(output_path) + '/img' + str(self.currFrame).zfill(
            int(np.ceil(np.log10(self.numberFrames)))) + '.png'
        labeled_img_name = str(output_path) + '/img' + str(
            self.currFrame).zfill(int(np.ceil(np.log10(
                self.numberFrames)))) + 'labeled.png'

        # Check for it output path and a machine label file exist
        if output_path.exists() and Path(self.machinefile).is_file():
            cv2.imwrite(img_name, frame)
            if self.savelabeled:
                self.figure.savefig(labeled_img_name, bbox_inches='tight')
            Data = pd.read_hdf(self.machinefile, 'df_with_missing')
            DataCombined = pd.concat([Data, DF])
            DataCombined = DataCombined[~DataCombined.index.duplicated(
                keep='first')]
            DataCombined.to_hdf(self.machinefile,
                                key='df_with_missing',
                                mode='w')
            DataCombined.to_csv(
                os.path.join(str(output_path), 'machinelabels.csv'))


# If machine label file does not exist then create one
        elif output_path.exists() and not (Path(self.machinefile).is_file()):
            if self.savelabeled:
                self.figure.savefig(labeled_img_name, bbox_inches='tight')
            cv2.imwrite(img_name, frame)
            DF.to_hdf(self.machinefile, key='df_with_missing', mode='w')
            DF.to_csv(os.path.join(str(output_path), "machinelabels.csv"))
        else:
            print(
                "%s path not found. Please make sure that the video was added to the config file using the function 'deeplabcut.add_new_videos'.Quitting for now!"
                % output_path)
            self.Destroy()

    def grabFrame(self, event):
        """
        Extracts the frame and saves in the current directory
        """

        if self.extract_range_frame == True:
            num_frames_extract = self.endFrame.GetValue()
            for i in range(self.currFrame,
                           self.currFrame + num_frames_extract):
                self.currFrame = i
                self.vid.set(1, self.currFrame)
                self.chooseFrame()
        else:
            self.vid.set(1, self.currFrame)
            self.chooseFrame()

    def plot_labels(self):
        """
        Plots the labels of the analyzed video
        """
        self.vid.set(1, self.currFrame)
        ret, frame = self.vid.read()
        self.norm, self.colorIndex = self.image_panel.getColorIndices(
            frame, self.bodyparts)
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            divider = make_axes_locatable(self.axes)
            cax = divider.append_axes("right", size="5%", pad=0.05)
            cbar = self.figure.colorbar(self.ax,
                                        cax=cax,
                                        spacing='proportional',
                                        ticks=self.colorIndex)
            cbar.set_ticklabels(self.bodyparts)
            for bpindex, bp in enumerate(self.bodyparts):
                color = self.colormap(self.norm(self.colorIndex[bpindex]))
                self.points = [
                    self.Dataframe[self.scorer][bp]['x'].values[
                        self.currFrame], self.Dataframe[self.scorer][bp]
                    ['y'].values[self.currFrame], 1.0
                ]
                circle = [
                    patches.Circle((self.points[0], self.points[1]),
                                   radius=self.markerSize,
                                   fc=color,
                                   alpha=self.alpha)
                ]
                self.axes.add_patch(circle[0])
            self.figure.canvas.draw()

    def helpButton(self, event):
        """
        Opens Instructions
        """
        wx.MessageBox(
            "1. Use the checkbox 'Crop?' at the bottom left if you need to crop the frame. In this case use the left mouse button to draw a box corresponding to the region of interest. Click the 'Set cropping parameters' button to add the video with the chosen crop parameters to the config file.\n\n2. Use the slider to select a frame in the entire video. \n\n3. Click Grab Frames button to save the specific frame.\n\n4. In events where you need to extract a range frames, then use the checkbox 'Range of frames' to select the starting frame index and the number of frames to extract. \n Click the update button to see the frame. Click Grab Frames to select the range of frames. \n Click OK to continue",
            'Instructions to use!', wx.OK | wx.ICON_INFORMATION)
class PlotFrame(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)
        
        self.figure = Figure(dpi=100)
        self.canvas = FigureCanvasTkAgg(self.figure,master=self)
        self.canvas.show()
        
        self.widget = self.canvas.get_tk_widget()
        self.widget.pack(side=TOP, expand=1, fill=BOTH)
        
        self.__plots = {}
        
        self.reset()
        
        self.bind("<Configure>", self._configure)
        
        self.config(background='red')
        
        self._scaledict = {}
        
        self._panmode = False
        self._xzoommode = False
        self._panstate = None
        
        self._padding = {}
        self._boundaries_changed = {}
        
        self.canvas.mpl_connect('button_press_event', self._button_pressed)
        self.canvas.mpl_connect('button_release_event', self._button_released)
        self.canvas.mpl_connect('motion_notify_event', self._motion)
        self.canvas.mpl_connect('scroll_event', self._scroll)

    def _scroll(self, event):
        if not event.inaxes:
            return
        
        for a in event.inaxes.get_children():
            z = 0
            if type(a) == YAxis and not self._xzoommode:
                self._scaledict[event.inaxes][1] = False
                z = 1 if (event.step > 0) else -1
            elif type(a) == XAxis and self._xzoommode:
                self._scaledict[event.inaxes][0] = False
                z = 1 if (event.step > 0) else -1
            
            if z != 0:
                a.zoom(z)
                self._boundaries_changed[event.inaxes] = True
                self._padding[event.inaxes] = [0, 0, 0, 0]
        
    def _button_pressed(self, event):
        if event.dblclick or not event.inaxes:
            if event.inaxes:
                self._panmode = False
                self._xzoommode = False
                self._panstate = None
                self._scaledict[event.inaxes] = [True, True]
                self._padding[event.inaxes] = [0, 0, 0, 0]
                self._boundaries_changed[event.inaxes] = False
                event.inaxes.set_ylim(auto=True)
                event.inaxes.set_xlim(auto=True)
                self.update()
            return
        
        self._panstate = [event.inaxes, event.x, event.y, 0, 0]
        
        if event.button == 1:
            self._panmode = True
        else:
            self._xzoommode = True
        
    def _button_released(self, event):
        self._xzoommode = False
        self._panmode = False
        self._panstate = None
    
    def _motion(self, event):
        if not self._panmode:
            return
        
        panx = False
        pany = False
        
        ps = self._panstate
        
        ps[3] += event.x - ps[1]
        ps[4] += event.y - ps[2]
        
        dx = ps[3]
        dy = ps[4]
        
        if abs(dx) > 5 and abs(dx) > abs(dy):
            panx = True
        elif abs(dy) > 5 and abs(dy) > abs(dx):
            pany = True
        
        for a in ps[0].get_children():
            p = 0
            if type(a) == YAxis and pany:
                self._scaledict[ps[0]][1] = False
                p = 1 if (dy < 0) else -1
            elif type(a) == XAxis and panx:
                self._scaledict[ps[0]][0] = False
                p = 1 if (dx < 0) else -1
            if p != 0:
                ps[3] = 0
                ps[4] = 0
                a.pan(p)
                self._boundaries_changed[ps[0]] = True
                self._padding[event.inaxes] = [0, 0, 0, 0]
        
        ps[1] = event.x
        ps[2] = event.y
        
        self._panstate = ps
        
    def update(self):
        for p in self.figure.axes:
            p.relim()
            p.autoscale_view(True, self._scaledict[p][0], self._scaledict[p][1])
                
            xi = p.get_xaxis().get_data_interval()
            yi = p.get_yaxis().get_data_interval()
            
            if self._boundaries_changed[p]:
                if not self._padding[p][0] and not self._scaledict[p][0]:
                    self._padding[p][0] = p.get_xlim()[0] - xi[0]
                if not self._padding[p][1] and not self._scaledict[p][0]:
                    self._padding[p][1] = p.get_xlim()[1] - xi[1]
                if not self._padding[p][2] and not self._scaledict[p][1]:
                    self._padding[p][2] = p.get_ylim()[0] - yi[0]
                if not self._padding[p][3] and not self._scaledict[p][1]:
                    self._padding[p][3] = p.get_ylim()[1] - yi[1]
            
            if self._padding[p][0] < 0:
                p.set_xlim(left=xi[0] + self._padding[p][0])
            
            if self._padding[p][1] > 0:
                p.set_xlim(right=xi[1] + self._padding[p][1])
            
            if self._padding[p][2] < 0:
                p.set_ylim(bottom=yi[0] + self._padding[p][2])
            
            if self._padding[p][3] > 0:
                p.set_ylim(top=yi[1] + self._padding[p][3])
            
        self.canvas.draw()
        
    
    def _configure(self, *args):
        width = self.winfo_width()
        height = self.winfo_height()
        
        w = width / 100.0
        h = height / 100.0
        
        self.figure.set_size_inches(w, h)
    
    def add_graph(self, graph, xdata=[], ydata=[]):
        if not graph.position in self.__plots:
            plt = self.figure.add_subplot(int(graph.position))
            plt.set_autoscale_on(True)
            self.__plots[graph.position] = plt
            plt.grid()
            self._scaledict[plt] = [True, True]
            self._padding[plt] = [0, 0, 0, 0]
            self._boundaries_changed[plt] = False
        
        graph.line, = self.__plots[graph.position].plot(xdata,ydata, graph.cfg)
        
        self.update_legends()
        
    def update_legends(self):
        lines = {}
        ids = {}
        for g in Graph.graphs.values():
            if not lines.has_key(g.position) or not ids.has_key(g.position):
                lines[g.position] = []
                ids[g.position] = []
            ids[g.position].append(g.identifier)
            lines[g.position].append(g.line)
        
        for p in lines.keys():
            if self.__plots.has_key(p):
                self.__plots[p].legend(lines[p], ids[p], 'upper left')
    
    def delete_graph(self, graph):
        graph.line.remove()
        for p in self.__plots.keys():
            if len(self.__plots[p].lines) == 0:
                self.figure.delaxes(self.__plots[p])
                del self.__plots[p]
            
    
    def update_graph(self, graph):
        xd = graph.line.get_xdata()
        yd = graph.line.get_ydata()
        self.delete_graph(graph)
        self.add_graph(graph)
        
    def clear_graph(self, graph):
        graph.line.remove()
        self.add_graph(graph, [], [])
    
    def reset(self):
        for p in self.figure.axes:
            self.figure.delaxes(p)
        self._scaledict = {}
        self.__plots = {}
        self._padding = {}
        self._boundaries_changed = {}
        self.figure.clf()
Exemple #53
0
class DOYPlot(FigureCanvas):

    def __str__(self):
        return "Stacked Day of Year Plot"

    def __init__(self, parent=None):
        ### Setup datasets
        # Actual data
        self.x = np.zeros(0)
        self.year = np.zeros(0)
        self.y = np.zeros(0)
        # Modeled fitted data
        self.mx = np.zeros(0)
        self.mx_year = np.zeros(0)
        self.my = np.zeros(0)
        # Location of pixel plotted
        self.px = None
        self.py = None

        # Store colorbar so we know to delete
        self.cbar = None
        # Store range of data
        self.yr_range = (0, 1)

        # Setup plots
        self.setup_plots()
        self.plot()

    def setup_plots(self):
        self.fig = Figure()
        self.axes = self.fig.add_subplot(111)
        FigureCanvas.__init__(self, self.fig)
        self.setAutoFillBackground(False)
        self.axes.set_ylim([0, 10000])
        self.fig.tight_layout()

    def update_plot(self):
        """ Fetches new information and then calls plot
        """
        self.px, self.py = tsm.ts.get_px(), tsm.ts.get_py()
        if self.px is not None and self.py is not None:
            # Add + 1 so we index on 1,1 instead of 0,0 (as in ENVI/MATLAB)
            self.px, self.py = self.px + 1, self.py + 1

        self.x = np.array([int(d.strftime('%j')) for d in tsm.ts.dates])
        self.year = np.array([d.year for d in tsm.ts.dates])
        self.y = tsm.ts.get_data(setting.plot['mask'])[setting.plot['band'], :]

        if setting.plot['fit'] is True and tsm.ts.result is not None:
            if len(tsm.ts.result) > 0:
                self.mx, self.my = tsm.ts.get_prediction(setting.plot['band'])
            else:
                self.mx, self.my = (np.zeros(0), np.zeros(0))

            self.mx_year = []
            for _mx in self.mx:
                self.mx_year.append(np.array([d.year for d in _mx]))

        if setting.plot['break'] is True and tsm.ts.result is not None:
            if len(tsm.ts.result) > 1:
                self.bx, self.by = tsm.ts.get_breaks(setting.plot['band'])
            else:
                self.bx, self.by = (np.zeros(0), np.zeros(0))
        self.plot()

    def plot(self):
        """ Matplotlib plot of time series stacked by DOY
        """
        self.axes.clear()

        title = 'Time series - row: {r} col: {c}'.format(
            r=str(self.py), c=str(self.px))
        self.axes.set_title(title)

        self.axes.set_xlabel('Day of Year')
        if tsm.ts is None:
            self.axes.set_ylabel('Band')
        else:
            self.axes.set_ylabel(tsm.ts.band_names[setting.plot['band']])

        self.axes.grid(True)
        self.axes.set_ylim([setting.plot['min'][setting.plot['band']],
                            setting.plot['max'][setting.plot['band']]])
        self.axes.set_xlim(0, 366)

        if setting.plot['xmin'] is not None \
                and setting.plot['xmax'] is not None:
            # Find array indexes for year range
            self.yr_range = np.arange(
                np.where(self.year >= setting.plot['xmin'])[0][0],
                np.where(self.year <= setting.plot['xmax'])[0][-1])
        else:
            self.yr_range = np.arange(0, self.year.shape[0])

        # Specify the year min and max
        yr_min = 0
        yr_max = 1
        if len(self.year) > 0:
            yr_min = self.year.min()
            yr_max = self.year.max()

        # Setup colormap and mapper
        cmap = mpl.cm.get_cmap('jet')
        norm = mpl.colors.Normalize(vmin=yr_min, vmax=yr_max)
        mapper = mpl.cm.ScalarMappable(norm=norm, cmap=cmap)

        # Plot
        sp = self.axes.scatter(self.x[self.yr_range], self.y[self.yr_range],
                               cmap=cmap, c=self.year[self.yr_range],
                               norm=norm,
                               marker='o', edgecolors='none', s=25,
                               picker=setting.plot['picker_tol'])

        # Only put colorbar if we have data
        if tsm.ts is not None:
            # Setup layout to add space
            # http://matplotlib.org/mpl_toolkits/axes_grid/users/overview.html#axesdivider
            divider = mpl_grid.make_axes_locatable(self.axes)
            cax = divider.append_axes('right', size='5%', pad=0.05)
            # Reset colorbar so it doesn't overwrite itself...
            if self.cbar is not None:
                self.fig.delaxes(self.fig.axes[1])
                self.fig.subplots_adjust(right=0.90)
            self.cbar = self.fig.colorbar(sp, cax=cax)

        if setting.plot['fit'] is True:
            med_year = []
            fit_plt = []
            # Find median year and plot that result
            for n, _yr in enumerate(self.mx_year):
                # Make sure _yr is not empty array
                if len(_yr) == 0:
                    continue
                # Determine median year
                med = int(np.median(_yr))
                # Make sure median year is in our current x-axis
                if setting.plot['xmin'] > med or setting.plot['xmax'] < med:
                    continue
                med_year.append(med)

                # Determine line color
                col = mapper.to_rgba(med)

                # Get index from mx predicted data for median year
                fit_range = np.arange(
                    np.where(_yr == med)[0][0],
                    np.where(_yr == med)[0][-1])

                # Recreate as DOY
                mx_doy = np.array([int(d.strftime('%j')) for d in
                                   self.mx[n][fit_range]])

                # Plot
                seg, = self.axes.plot(mx_doy, self.my[n][fit_range],
                                      color=col, linewidth=2)
                fit_plt.append(seg)

            if len(med_year) > 0:
                self.axes.legend(fit_plt,
                                 ['Fit {n}: {y}'.format(n=n + 1, y=y)
                                  for n, y in enumerate(med_year)])

        # Redraw
        self.fig.tight_layout()
        self.fig.canvas.draw()

    def save_plot(self):
        """ Save the matplotlib figure
        """
        ### Parse options from settings
        fname = setting.save_plot['fname']
        fformat = setting.save_plot['format']
        facecolor = setting.save_plot['facecolor']
        edgecolor = setting.save_plot['edgecolor']
        transparent = setting.save_plot['transparent']
        ### Format the output path
        directory = os.path.split(fname)[0]
        # Check for file extension
        if '.' not in os.path.split(fname)[1]:
            filename = '{f}.{e}'.format(f=os.path.split(fname)[1], e=fformat)
        # Add in directory if none
        if directory == '':
            directory = '.'
        # If directory does not exist, return False
        if not os.path.exists(directory):
            return False
        # Join and save
        filename = os.path.join(directory, filename)

        self.fig.savefig(filename, format=fformat,
                         facecolor=facecolor, edgecolor=edgecolor,
                         transparent=transparent)

        return True

    def disconnect(self):
        pass
Exemple #54
0
class GraphPanel(wx.Panel):
    def __init__(self,parent,ctrl):
        wx.Panel.__init__(self,parent)
        self.SetBackgroundColour('#FFFFFF')
        self.ctrlPanel = ctrl
        self.initGraph()
        wx.EVT_PAINT(self, self.OnPaint)


    def initGraph(self):
        self.x0 = []
        self.y0 = []
        self.x1 = []
        self.y1 = []
        self.x2 = []
        self.y2 = []
        self.trial = 1
        
        self.figure = Figure(dpi=100,figsize=(5,8))
        self.axes = self.figure.add_subplot(111)
        self.axes.axis([0,self.ctrlPanel.experimentDuration,1,0])
        self.axes.set_xlabel('time (s)')

        bluepts = self.axes.scatter(self.x0, self.y0, c='b',s=10,lw=0.0)
        redpts = self.axes.scatter(self.x1,self.y1, c='r',s=10,lw=0.0)
        purpts = self.axes.scatter(self.x2,self.y2,c='m',s=10,lw=0.0)

        startAt = self.ctrlPanel.iti
        endAt = startAt+self.ctrlPanel.toneDuration
        tone = self.axes.axvspan(startAt,endAt,facecolor='g',alpha=0.5,lw=0.0)
        startAt = endAt
        endAt = startAt+self.ctrlPanel.wait
        wait = self.axes.axvspan(startAt,endAt,facecolor='#aeaeae',alpha=0.5,lw=0.0)
        startAt = endAt
        endAt = startAt + self.ctrlPanel.rewardInterval
        reward = self.axes.axvspan(startAt,endAt,facecolor='#FFCCCC',alpha=0.5,lw=0.0)

        LText = FontProperties()
        LText.set_size("small")
        
        self.axes.legend((bluepts,redpts,purpts,tone,wait,reward),
                         ("Lever Press","Rewarded Press","Manual Reward","Tone Duration","Wait Interval","Reward Interval"),
                         prop=LText, fancybox=True, bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0)

        self.canvas = FigureCanvas(self, -1, self.figure)
    
    def clearGraph(self):
        self.figure.delaxes(self.axes)
        self.initGraph()
        self.Refresh()
    
    def addPoint(self,t,pcat):
        if pcat==1:
            self.x1.append(t)
            self.y1.append(self.trial)
            self.trial+=1
            self.axes.set_ylim(bottom=self.trial)
        elif pcat==2:
            self.x2.append(t)
            self.y2.append(self.trial)
            self.trial+=1
            self.axes.set_ylim(bottom=self.trial)
        else:
            self.x0.append(t)
            self.y0.append(self.trial)
    
        
    def OnPaint(self, event):

        self.bluepts = self.axes.scatter(self.x0, self.y0, c='b',s=10,lw=0.0)
        self.redpts = self.axes.scatter(self.x1,self.y1, c='r',s=10,lw=0.0)
        self.purpts = self.axes.scatter(self.x2,self.y2,c='m',s=10,lw=0.0)
        self.canvas.draw()
        event.Skip()

    def OnSetFocus(self, event):
        #self.color = '#0099f7'
        self.color = 'yellow'
        self.Refresh()

    def OnKillFocus(self, event):
        self.color = '#b3b3b3'
        self.Refresh()
Exemple #55
0
class Window(QtGui.QApplication):
    """This class holds/is the main windows of the GUI"""

    EXIT_CODE_REBOOT = -666

    def __init__(self, sys_argv):
        """Inits/ Builds the GUI"""
        super(Window, self).__init__(sys_argv)

        #----------------------------Setting path to resources folder----------------------------#
        current_path = os.path.realpath(__file__)
        current_path = current_path.split("\\")
        pathToProgramm = current_path[:-2 or None]
        self.path = ""
        for s in pathToProgramm:
            self.path += s + "\\"

        #----------------------------Validator for float inputs----------------------------#
        regexp_onlyDoubles = QtCore.QRegExp('^([-+]?\d*\.\d+|\d+)$')
        self.validator = QtGui.QRegExpValidator(regexp_onlyDoubles)

        #----------------------------Variablen----------------------------#

        self.potenzialnummer = 2
        self.potenzialList = []
        self.currentPotenzial = 1
        self.wasFullyConnectedBeforeUndo = []
        self.potencial = 0

        self.controler = controler.Controler()

        #----------------------------Init Main Window----------------------------#

        cssFile = "../resources/css-gui.txt"
        css = ""
        with open(cssFile, "r") as fh:
            css += (fh.read())

        screen_resolution = self.desktop().screenGeometry()
        width, height = screen_resolution.width(), screen_resolution.height()

        self.main_window = QtGui.QMainWindow()
        self.main_window.setWindowTitle('ECS - Electronical Circuit Simulator')
        self.main_window.showMaximized()

        #Set Icon
        self.setAppIcon()

        # set the layout
        containerMain = QtGui.QWidget()
        containerMain.setObjectName("containerMain")

        containerMain.setStyleSheet(css)
        self.main_window.setStyleSheet(css)
        mainLayout = QtGui.QVBoxLayout(containerMain)

        containerGraph = QtGui.QWidget()
        containerGraph.setObjectName("containerGraph")
        containerGraph.setFixedWidth(width * 0.965)

        graphLayout = QtGui.QVBoxLayout(containerGraph)

        containerCircuit = QtGui.QWidget()

        containerCircuit.setObjectName("containerCircuit")
        containerCircuit.setFixedWidth(width * 0.7)
        containerCircuit.setFixedHeight(height * 0.4)

        circuitLayout = QtGui.QVBoxLayout(containerCircuit)

        containerInput = QtGui.QWidget()
        containerInput.setObjectName("containerInput")

        containerInput.setFixedWidth(width * 0.25)
        containerInput.setFixedHeight(height * 0.4)
        inputLayout = QtGui.QVBoxLayout(containerInput)

        containerUpperLayout = QtGui.QWidget()
        upperLayout = QtGui.QHBoxLayout(containerUpperLayout)

        containerLowerLayout = QtGui.QWidget()
        lowerLayout = QtGui.QHBoxLayout(containerLowerLayout)
        containerLowerLayout.setFixedHeight(height * 0.4)

        #----------------------------Main-Menue------------------------------#

        self.setMenu()
        self.createDropDowns()
        #----------------------------Graph-Layout----------------------------#

        self.figure = Figure()
        self.canvas = FigureCanvas(self.figure)

        self.toolbar = NavigationToolbar(self.canvas, containerGraph)

        self.buttonPlotPotenzial = QtGui.QPushButton('Plot Potenzial ')
        self.buttonPlotPotenzial.clicked.connect(self.plot2)
        self.buttonPlotPotenzial.hide()
        self.buttonPlotPotenzial.setFixedSize(120, 20)

        graphInputLayout = QtGui.QHBoxLayout()
        graphInputLayout.addWidget(self.potenzialDropDown)
        graphInputLayout.addWidget(self.buttonPlotPotenzial)

        graphInputWidget = QtGui.QWidget()
        graphInputWidget.setLayout(graphInputLayout)
        graphInputWidget.setFixedSize(350, 30)

        graphLayout.addWidget(self.toolbar)
        graphLayout.addWidget(graphInputWidget)
        graphLayout.addWidget(self.canvas)

        #----------------------------Circuit-Layout----------------------------#

        self.createCircuitFigure()
        circuitLayout.setContentsMargins(20, 20, 20, 20)
        circuitLayout.addWidget(self.scrollArea)

        #----------------------------Input-Layout----------------------------#

        inputNameLayout = QtGui.QHBoxLayout()

        self.createFunctionDropwDowns()

        self.componentNameInputLabel = QtGui.QLabel("Name des Bauteils")

        self.componentNameInput = QtGui.QLineEdit()
        self.componentNameInput.setObjectName("")
        self.componentNameInput.setText("")

        inputNameLayout.addWidget(self.componentNameInputLabel)
        inputNameLayout.addWidget(self.componentNameInput)

        inputComponentLayout = QtGui.QHBoxLayout()
        inputComponentLayout.addWidget(self.componentDropwDown)
        inputComponentLayout.addWidget(self.potenzialDropDownFrom)
        inputComponentLayout.addWidget(self.potenzialDropDownTo)

        inputComponentLayout2 = QtGui.QHBoxLayout()

        self.directionLabel = QtGui.QLabel("Direction")
        inputComponentLayout2.addWidget(self.directionLabel)
        inputComponentLayout2.addWidget(self.directionDropwDown)

        inputComponentLayout3 = QtGui.QHBoxLayout()

        self.componentValueLabel = QtGui.QLabel("Start-Value of Component")
        self.componentValueLabel.hide()
        self.componentValueInput = QtGui.QLineEdit()
        self.componentValueInput.setObjectName("")
        self.componentValueInput.setText("0.0")
        self.componentValueInput.hide()
        self.componentValueInput.setValidator(self.validator)
        #self.componentValueInput.textEdited.connect(self.on_valueInputChanged)

        inputComponentLayout3.addWidget(self.componentValueLabel)
        inputComponentLayout3.addWidget(self.componentValueInput)
        inputComponentLayout3.addWidget(self.function_c_DropwDown)
        inputComponentLayout3.addWidget(self.function_i_DropwDown)
        inputComponentLayout3.addWidget(self.function_r_DropwDown)
        inputComponentLayout3.addWidget(self.function_v_DropwDown)
        inputComponentLayout3.addWidget(self.function_l_DropwDown)

        buttonAddComponent = QtGui.QPushButton('Add Component')
        buttonAddComponent.clicked.connect(self.addComponentToCircuit)
        buttonUndo = QtGui.QPushButton('Simulate')
        buttonUndo.clicked.connect(self.enterPotencialValues)

        inputLayout.addLayout(inputNameLayout)
        inputLayout.addLayout(inputComponentLayout)
        inputLayout.addLayout(inputComponentLayout2)
        inputLayout.addLayout(inputComponentLayout3)

        inputLayout.addWidget(buttonAddComponent)
        inputLayout.addWidget(buttonUndo)

        inputLayout.setContentsMargins(50, 50, 50, 50)

        #----------------------------Main-Layout----------------------------#

        upperLayout.addWidget(containerInput)
        upperLayout.addWidget(containerCircuit)

        lowerLayout.addWidget(containerGraph)

        mainLayout.addWidget(containerUpperLayout)
        mainLayout.addWidget(containerLowerLayout)

        self.main_window.setCentralWidget(containerMain)

        self.createNewCircuit()

    def setAppIcon(self):
        """This function loads and sets the application icon"""

        app_icon = QtGui.QIcon()
        app_icon.addFile("..\\resources\\favicon.ico")
        app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(16, 16))
        app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(24, 24))
        app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(32, 32))
        app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(48, 48))
        app_icon.addFile("..\\resources\\favicon.ico", QtCore.QSize(256, 256))
        self.setWindowIcon(QtGui.QIcon("..\\resources\\favicon.ico"))
        self.main_window.setWindowIcon(app_icon)

    def setMenu(self):
        """This function create the Window-Menue"""

        self.statusbar = self.main_window.statusBar()

        mainMenu = self.main_window.menuBar()

        fileMenu = mainMenu.addMenu("&File")
        editMenu = mainMenu.addMenu("&Edit")

        createNewAction = QtGui.QAction("New", self.main_window)
        createNewAction.setShortcut("Ctrl+N")
        createNewAction.setStatusTip("Create a new Circuit")
        createNewAction.triggered.connect(self.createNewCircuit)

        exitAction = QtGui.QAction("Exit", self.main_window)
        exitAction.setShortcut("Ctrl+Q")
        exitAction.setStatusTip("Leave the Applikation")
        exitAction.triggered.connect(self.closeApplication)

        saveAction = QtGui.QAction("Save", self.main_window)
        saveAction.setShortcut("Ctrl+S")
        saveAction.setStatusTip("Save the Applikation")
        saveAction.triggered.connect(self.save)

        loadAction = QtGui.QAction("Load", self.main_window)
        loadAction.setShortcut("Ctrl+O")
        loadAction.setStatusTip("Load the Applikation")
        loadAction.triggered.connect(self.load)

        undoAction = QtGui.QAction("Undo", self.main_window)
        undoAction.setShortcut("Ctrl+Z")
        undoAction.setStatusTip("Undo the last Action")
        undoAction.triggered.connect(self.undo)

        fileMenu.addAction(createNewAction)
        fileMenu.addAction(saveAction)
        fileMenu.addAction(loadAction)
        fileMenu.addAction(exitAction)
        editMenu.addAction(undoAction)
        mainMenu.setObjectName("mainMenu")
        mainMenu.setStyleSheet(
            "#mainMenu{padding: 3px; border-bottom: 2px solid #0F9BA8; background-color:white}"
        )

    def createFunctionDropwDowns(self):
        """This function creates the Drop-Downs for Function selection based ond the funcitonLib"""

        all_functions = inspect.getmembers(functionLib, inspect.isfunction)

        self.c_functions = []
        self.i_functions = []
        self.r_functions = []
        self.v_functions = []
        self.l_functions = []

        for functionTupel in all_functions:
            if "c_" in functionTupel[0]:
                self.c_functions.append(functionTupel)

            elif "i_" in functionTupel[0]:
                self.i_functions.append(functionTupel)
            elif "r_" in functionTupel[0]:
                self.r_functions.append(functionTupel)
            elif "v_" in functionTupel[0]:
                self.v_functions.append(functionTupel)
            elif "l_" in functionTupel[0]:
                self.l_functions.append(functionTupel)

        self.function_c_DropwDown = QtGui.QComboBox()
        self.function_c_DropwDown.addItem("Choose Function")
        self.function_i_DropwDown = QtGui.QComboBox()
        self.function_i_DropwDownNew = QtGui.QComboBox()
        self.function_i_DropwDown.addItem("Choose Function")
        self.function_i_DropwDownNew.addItem("Choose Function")
        self.function_r_DropwDown = QtGui.QComboBox()
        self.function_r_DropwDown.addItem("Choose Function")
        self.function_v_DropwDown = QtGui.QComboBox()
        self.function_v_DropwDownNew = QtGui.QComboBox()
        self.function_v_DropwDown.addItem("Choose Function")
        self.function_v_DropwDownNew.addItem("Choose Function")
        self.function_l_DropwDown = QtGui.QComboBox()
        self.function_l_DropwDown.addItem("Choose Function")

        for functionTupel in self.c_functions:
            self.function_c_DropwDown.addItem(functionTupel[0])

        for functionTupel in self.i_functions:
            self.function_i_DropwDown.addItem(functionTupel[0])
            self.function_i_DropwDownNew.addItem(functionTupel[0])

        for functionTupel in self.r_functions:
            self.function_r_DropwDown.addItem(functionTupel[0])

        for functionTupel in self.v_functions:
            self.function_v_DropwDown.addItem(functionTupel[0])
            self.function_v_DropwDownNew.addItem(functionTupel[0])

        for functionTupel in self.l_functions:
            self.function_l_DropwDown.addItem(functionTupel[0])

        self.function_c_DropwDown.hide()
        self.function_i_DropwDown.hide()
        #self.function_r_DropwDown.hide()
        self.function_v_DropwDown.hide()
        self.function_l_DropwDown.hide()

    def createCircuitFigure(self):
        """This function creates the visiual representation of the circuit"""

        self.circuitFigure = Figure()
        self.circuitCanvas = FigureCanvas(self.circuitFigure)

        self.image = QtGui.QLabel()
        self.image.setGeometry(50, 40, 250, 250)

        self.image.setObjectName("imageCircuit")

        self.scrollArea = QtGui.QScrollArea()
        self.scrollArea.setWidget(self.image)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollCircuit")

    def createDropDowns(self):
        """This function creates multile Drop-Downs for the GUI. Mostly used for the input of components"""

        self.componentDropwDown = QtGui.QComboBox()
        self.componentDropwDown.addItem("Resistor")
        self.componentDropwDown.addItem("Coil")
        self.componentDropwDown.addItem("Capacitator")
        self.componentDropwDown.addItem("V-Source")
        self.componentDropwDown.addItem("I-Source")
        self.componentDropwDown.currentIndexChanged.connect(
            self.on_ComponentChanged)

        self.potenzialDropDownFrom = QtGui.QComboBox()
        self.potenzialDropDownFrom.addItem("---Potencial From---")
        self.potenzialDropDownFrom.addItem("E-Last")
        self.potenzialDropDownFrom.addItem("E-Masse")
        self.potenzialDropDownFrom.setAutoCompletion(True)

        self.potenzialDropDownTo = QtGui.QComboBox()
        self.potenzialDropDownTo.addItem("---Potencial To---")
        self.potenzialDropDownTo.addItem("E-Last")
        self.potenzialDropDownTo.addItem("E-Masse")
        self.potenzialDropDownFrom.setAutoCompletion(True)

        self.directionDropwDown = QtGui.QComboBox()
        self.directionDropwDown.addItem("left")
        self.directionDropwDown.addItem("right")
        self.directionDropwDown.addItem("up")
        self.directionDropwDown.addItem("down")

        self.potenzialDropDown = QtGui.QComboBox()
        self.potenzialDropDown.setFixedSize(200, 20)
        self.potenzialDropDown.hide()
        self.potenzialDropDown.currentIndexChanged.connect(
            self.onPotencialChanged)

    def onPotencialChanged(self):
        """Sets the choosen potencial for plotting graph when Potencial-Drop-Down changed"""
        self.potencial = self.potenzialDropDown.currentIndex()

    def createNewCircuit(self):
        """This function handels the initial creating dialog for creating a new circuit"""

        all_functions = inspect.getmembers(functionLib, inspect.isfunction)
        print(all_functions)

        self.i_functions = []
        self.v_functions = []

        for functionTupel in all_functions:

            if "i_" in functionTupel[0]:
                self.i_functions.append(functionTupel)

            elif "v_" in functionTupel[0]:
                self.v_functions.append(functionTupel)

        self.function_i_DropwDownNew = QtGui.QComboBox()
        self.function_i_DropwDownNew.addItem("Choose Function")
        self.function_v_DropwDownNew = QtGui.QComboBox()
        self.function_v_DropwDownNew.addItem("Choose Function")

        for functionTupel in self.i_functions:
            self.function_i_DropwDownNew.addItem(functionTupel[0])

        for functionTupel in self.v_functions:
            self.function_v_DropwDownNew.addItem(functionTupel[0])

        self.function_v_DropwDownNew.hide()
        self.function_i_DropwDownNew.show()
        self.initParametersDialog = QtGui.QDialog()

        layout = QtGui.QFormLayout()

        startLabel = QtGui.QLabel("Choose a start Circuit")

        self.choosen = 0

        self.beginningCircuit = QtGui.QComboBox()
        self.beginningCircuit.addItem("Start with a I-Source")
        self.beginningCircuit.addItem("Start with a V-Source")
        self.beginningCircuit.currentIndexChanged.connect(
            self.onNewDropChanged)

        okButton = QtGui.QPushButton("Create New Circuit")
        okButton.clicked.connect(self.setStartingValues)

        layout.addRow(startLabel, self.beginningCircuit)
        layout.addWidget(self.function_v_DropwDownNew)
        layout.addWidget(self.function_i_DropwDownNew)
        layout.addRow(okButton)
        self.initParametersDialog.setLayout(layout)
        self.initParametersDialog.setWindowTitle("Create a new Circuit")

        self.initParametersDialog.exec()

        self.controler = controler.Controler()
        self.controler.createCircuit(self.choosen, self.function)

        self.potenzialDropDownFrom.clear()
        self.potenzialDropDownFrom.addItem("---Ausgangspotenzial---")
        self.potenzialDropDownFrom.addItem("E-Last")
        self.potenzialDropDownFrom.addItem("E-Masse")

        self.potenzialDropDownTo.clear()
        self.potenzialDropDownTo.addItem("---Eingangspotenzial---")
        self.potenzialDropDownTo.addItem("E-Last")
        self.potenzialDropDownTo.addItem("E-Masse")

        self.updateGraph()

    def setStartingValues(self):
        """Sets function when function-drop-downs changed. It has influence on the function for the starting element"""
        if self.choosen == 0:
            self.function = self.function_i_DropwDownNew.currentText()
        else:
            self.function = self.function_v_DropwDownNew.currentText()
        self.initParametersDialog.close()

    def onNewDropChanged(self):
        """Sets choosen when beginningCircuit - drop-down changed. It determins if the starting element is a voltage or a power-source"""
        self.choosen = self.beginningCircuit.currentIndex()
        if self.choosen == 1:
            self.function_v_DropwDownNew.show()
            self.function_i_DropwDownNew.hide()

        else:
            self.function_i_DropwDownNew.show()
            self.function_v_DropwDownNew.hide()

    def save(self):
        """Saves the current project / current simulation without the simulation data"""

        objectsToSave = [
            self.controler,
            [
                self.potenzialDropDownFrom.itemText(i)
                for i in range(self.potenzialDropDownFrom.count())
            ],
            [
                self.potenzialDropDownTo.itemText(i)
                for i in range(self.potenzialDropDownTo.count())
            ]
        ]
        pathFileName = QtGui.QFileDialog.getSaveFileName(
            None, 'Load ECS-Project', self.path + '\\saved-circuits',
            'pickle(*.pickle)')

        with open(pathFileName, 'wb') as handle:
            pickle.dump(objectsToSave,
                        handle,
                        protocol=pickle.HIGHEST_PROTOCOL)

        messagebox = timedMessage.TimerMessageBox("Information",
                                                  "File successfully saved", 3,
                                                  self.main_window)
        messagebox.exec_()

        self.statusbar.showMessage("File successfully saved", 5000)

    def load(self):
        """This function handels the loading of a circuit"""

        self.potenzialDropDown.hide()
        self.buttonPlotPotenzial.hide()

        pathFileName = QtGui.QFileDialog.getOpenFileName(
            None, 'Load ECS-Project', self.path + '\\saved-circuits',
            'pickle(*.pickle)')
        with open(pathFileName, 'rb') as handle:
            loadedObjects = pickle.load(handle)

        messagebox = timedMessage.TimerMessageBox("Informaion",
                                                  "File successfully loaded",
                                                  2, self.main_window)
        messagebox.exec_()

        self.statusbar.showMessage("File successfully loaded", 5000)

        self.controler = loadedObjects[0]
        self.controler.drawCircuit()
        self.updateGraph()
        self.potenzialDropDownFrom.clear()
        self.potenzialDropDownTo.clear()

        self.potenzialDropDownFrom.addItems(loadedObjects[1])
        self.potenzialDropDownTo.addItems(loadedObjects[2])

    def closeApplication(self):
        """Closes the GUI"""
        self.quit()

    def undo(self):
        """Undo the last modification to the circuit"""

        haveToRemove = self.controler.undoAddComponent()

        if haveToRemove:

            self.potenzialDropDownFrom.removeItem(
                self.potenzialDropDownFrom.count() - 1)
            self.potenzialDropDownTo.removeItem(
                self.potenzialDropDownTo.count() - 1)

        self.updateGraph()

    """def on_valueInputChanged(self):
        self.componentValueDropDown.setCurrentIndex(0)"""

    def on_valueDropDownChanged(self):
        """Resets the written component value"""
        self.componentValueInput.setText("")

    def on_ComponentChanged(self):
        """Makes certain input-field visible and hide others if the user selectets a different component"""

        self.function_c_DropwDown.hide()
        self.function_i_DropwDown.hide()
        self.function_r_DropwDown.hide()
        self.function_v_DropwDown.hide()
        self.function_l_DropwDown.hide()

        self.componentValueInput.hide()
        self.componentValueLabel.hide()

        if self.componentDropwDown.currentText() == "Coil":
            self.componentValueInput.setText("0.0")
            self.componentValueInput.show()
            self.componentValueLabel.show()

            self.function_l_DropwDown.show()

        elif self.componentDropwDown.currentText() == "Resistor":
            self.function_r_DropwDown.show()

        elif self.componentDropwDown.currentText() == "Capacitator":
            self.function_c_DropwDown.show()

        elif self.componentDropwDown.currentText() == "V-Source":
            self.function_v_DropwDown.show()

        elif self.componentDropwDown.currentText() == "I-Source":
            self.function_i_DropwDown.show()

    #else:
    #self.componentValueInput.hide()
    #self.componentValueLabel.hide()

    def addComponentToCircuit(self):
        """Handels the adding of a new component to the circuit"""

        component = (str(self.componentDropwDown.currentText()))
        function = "0"

        if component == "Capacitator":
            function = self.function_c_DropwDown.currentText()

        if component == "I-Source":
            function = self.function_i_DropwDown.currentText()

        if component == "Resistor":
            function = self.function_r_DropwDown.currentText()

        if component == "V-Source":
            function = self.function_v_DropwDown.currentText()

        if component == "Coil":
            function = self.function_l_DropwDown.currentText()

        direction = (str(self.directionDropwDown.currentText()))
        name = (str(self.componentNameInput.text()))

        elabel = self.controler.addComponent(
            component, direction, name,
            self.potenzialDropDownFrom.currentIndex(),
            self.potenzialDropDownTo.currentIndex(),
            self.componentValueInput.text(), function)

        if len(elabel) > 0:
            self.potenzialDropDownFrom.addItem(elabel)
            self.potenzialDropDownTo.addItem(elabel)

        self.potenzialDropDownFrom.setCurrentIndex(0)
        self.potenzialDropDownTo.setCurrentIndex(0)
        self.componentValueInput.setText("0.0")
        self.componentValueInput.hide()
        self.componentValueLabel.hide()

        self.updateGraph()

    def updateGraph(self):
        """Updates the current visual representation of the circuit"""

        self.pixmap = QtGui.QPixmap("..\\resources\\ergebnis.png")
        self.image.setPixmap(self.pixmap)

    def simulate(self):
        """Collects all nessesary inputs to the start the simulation and starts it"""

        self.potenzialDropDown.clear()
        for x in range(len(self.list_potencialInputs)):
            self.controler.addPotencialValue(
                "E" + str(x), self.list_potencialInputs[x].text())

        self.controler.setTValues(float(self.list_timeInputs[0].text()),
                                  float(self.list_timeInputs[1].text()))

        self.potenzialParameters.close()

        try:
            self.controler.writeNetList("Schaltung.txt")
            self.controler.simulate("Schaltung.txt")
            qt = QtGui.QMessageBox()
            qt.setIcon(QtGui.QMessageBox.Information)
            qt.setWindowTitle("Info")
            qt.setText("Simulation was successfull!")
            qt.exec()
        except:
            qt = QtGui.QMessageBox()
            qt.setIcon(QtGui.QMessageBox.Critical)
            qt.setWindowTitle("An Error Occured")
            qt.setText(
                "The circuit could not be simulated \nThe circuit might not be valid"
            )
            qt.exec()

        for potencial in range(len(self.potenzialDropDownFrom) - 2):
            self.potenzialDropDown.addItem("Potencial " + str(potencial + 1))

        self.potenzialDropDown.show()
        self.buttonPlotPotenzial.show()

    def enterPotencialValues(self):
        """Creates the input fields for the starting values of the simulation"""

        self.potenzialParameters = QtGui.QDialog()

        layout = QtGui.QFormLayout()

        label_t = QtGui.QLabel("Please insert the time to simulate")
        t_input = QtGui.QLineEdit()
        t_input.setObjectName("")
        t_input.setText("1.0")
        t_input.setValidator(self.validator)

        label_t_steps = QtGui.QLabel(
            "Please insert the steps you want to split the time")
        t_steps_input = QtGui.QLineEdit()
        t_steps_input.setObjectName("")
        t_steps_input.setText("1.0")
        t_steps_input.setValidator(self.validator)

        layout.addRow(label_t, t_input)
        layout.addRow(label_t_steps, t_steps_input)

        self.list_timeInputs = [t_input, t_steps_input]

        label_infoPotencial = QtGui.QLabel(
            "Please insert start-value (float) for the potencials")
        self.list_potencialInputs = []

        for potencial in range(len(self.potenzialDropDownFrom) - 2):
            inputPotencialLayout = QtGui.QHBoxLayout()

            potencialValueLabel = QtGui.QLabel("Value of Potencial:" +
                                               str(potencial))

            potencialValueInput = QtGui.QLineEdit()
            potencialValueInput.setObjectName("")
            potencialValueInput.setText("1.0")
            potencialValueInput.setValidator(self.validator)
            inputPotencialLayout.addWidget(potencialValueLabel)
            inputPotencialLayout.addWidget(potencialValueInput)
            layout.addRow(inputPotencialLayout)
            self.list_potencialInputs.append(potencialValueInput)

        button_startSimulation = QtGui.QPushButton("Start Simulation")
        button_startSimulation.clicked.connect(self.simulate)
        layout.addRow(button_startSimulation)

        self.potenzialParameters.setLayout(layout)
        self.potenzialParameters.setWindowTitle("Potencial Values")

        self.potenzialParameters.exec()

    def plot2(self):
        """Plots the simulated data for a choosen potencial"""

        x = []
        y = []
        data = self.controler.getSolutionData()

        for entry in data:

            x.append(entry[0][0][self.potencial])
            y.append(entry[1])

        ax = self.figure.add_subplot(111)

        ax.clear()

        ax.set_xlabel("Time")
        ax.set_ylabel("Potencial Value")

        ax.plot(y, x)
        self.figure.tight_layout()

        self.canvas.draw()
        self.figure.delaxes(ax)
class Qt4Mpl2dCanvas(FigureCanvas):
    """  A customized Qt widget for matplotlib 2D image.
    It can be used to replace GraphicsView
    """

    def __init__(self, parent):
        """  Initialization
        """
        # Instantiating matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')

        self.axes = self.fig.add_subplot(111) # return: matplotlib.axes.AxesSubplot

        # Initialize parent class and set parent
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        # legend and color bar
        self._colorBar = None

        # Buffer of data
        self._currentArray2D = None

        # image management data structure
        self._currIndex = 0
        self._imagePlotDict = dict()

        # image size
        self._xLimit = [0., 1.]
        self._yLimit = [0., 1.]

        return

    @property
    def array2d(self):
        """
        get the matrix plot now
        :return:
        """
        return self._currentArray2D

    def add_2d_plot(self, array2d, x_min, x_max, y_min, y_max, hold_prev, yticklabels=None):
        """ Add a 2D plot
        Requirements:
        (1) a valid 2-dimensional numpy.ndarray
        (2) x_min, x_max, y_min, y_max are of right order
        Guarantees: a 2D fill-plot is made
        :param array2d:
        :param x_min:
        :param x_max:
        :param y_min:
        :param y_max:
        :param hold_prev: hold previous image.  If False, all 2D image and polygon patches will be removed
        :param yticklabels: list of string for y ticks
        :return:
        """
        # Check
        assert isinstance(array2d, np.ndarray), 'Input array2d must be a numpy array but not %s.' % str(type(array2d))
        assert isinstance(x_min, int) and isinstance(x_max, int) and x_min < x_max, \
            'x_min = %s (of type %s) should be less than x_max = %s (of type %s).' \
            '' % (str(x_min), str(type(x_min)), str(x_max), str(type(x_max)))
        assert isinstance(y_min, int) and isinstance(y_max, int) and y_min < y_max

        # Release the current image
        self.axes.hold(hold_prev)

        # show image
        img_plot = self.axes.imshow(array2d,
                                    extent=[x_min, x_max, y_min, y_max],
                                    interpolation='none')
        self._currentArray2D = array2d

        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            # FUTURE-VZ : The way to set up the Y-axis ticks is wrong!"
            # self.axes.set_yticklabels(yticklabels)
            print('[Warning] The method to set up the Y-axis ticks to 2D image is wrong!')

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            img_plot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(img_plot)
        else:
            self._colorBar.update_bruteforce(img_plot)

        # Flush...
        self._flush()

        # Add the image management
        self._currIndex += 1
        self._imagePlotDict[self._currIndex] = img_plot

        return self._currIndex

    def add_patch(self, patch):
        """
        add an artist patch such as polygon
        :param patch:
        :return:
        """
        self.axes.add_artist(patch)

        # Flush...
        self._flush()

        return

    def addImage(self, imagefilename):
        """ Add an image by file
        """
        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        self._flush()

        return

    def clear_canvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        self.axes.hold(False)

        # clear 2D image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self._colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)
        # END-FOR

        # flush/commit
        self._flush()

        return

    def plot_polygon(self, vertex_array, fill=False, color='w'):
        """
        Plot a new polygon
        :param vertex_array:
        :param fill:
        :param color:
        :return:
        """
        # check requirements
        assert isinstance(vertex_array, np.ndarray)
        assert isinstance(fill, bool)
        assert isinstance(color, str)

        # plot polygon
        p = plt.Polygon(vertex_array, fill=fill, color=color)
        self.axes.add_artist(p)

        # Flush...
        self._flush()

        return p

    @property
    def x_min(self):
        """ x minimum
        :return:
        """
        return self._xLimit[0]

    @property
    def x_max(self):
        """ maximum x
        :return:
        """
        return self._xLimit[1]

    @property
    def y_min(self):
        """ minimum y
        :return:
        """
        return self._yLimit[0]

    @property
    def y_max(self):
        """ maximum y
        :return:
        """
        return self._yLimit[1]

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w+1, h)
        self.resize(w, h)

        return
Exemple #57
0
class FigureCanvas(FigureCanvasQTAgg):
    """  A customized Qt widget for matplotlib figure.
    It can be used to replace GraphicsView of QtGui
    """
    def __init__(self, parent):
        self._driver = AddieDriver()
        # from mpl_toolkits.axes_grid1 import host_subplot
        # import mpl_toolkits.axisartist as AA
        # import matplotlib.pyplot as plt

        # Instantiating matplotlib Figure
        self.fig = Figure()
        self.fig.patch.set_facecolor('white')

        self.axes = self.fig.add_subplot(111, projection='mantid')
        self.fig.subplots_adjust(bottom=0.15)

        # Initialize parent class and set parent
        FigureCanvasQTAgg.__init__(self, self.fig)
        self.setParent(parent)

        # Set size policy to be able to expanding and resizable with frame
        FigureCanvasQTAgg.setSizePolicy(self, QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        FigureCanvasQTAgg.updateGeometry(self)

        # Variables to manage all lines/subplot
        self._lineDict = {}
        self._lineIndex = 0

        # legend and color bar
        self._colorBar = None
        self._isLegendOn = False
        self._legendFontSize = 10

    @property
    def is_legend_on(self):
        """
        check whether the legend is shown or hide
        """
        return self._isLegendOn

    def add_arrow(self, start_x, start_y, stop_x, stop_y):
        """
        0, 0, 0.5, 0.5, head_width=0.05, head_length=0.1, fc='k', ec='k')
        :return:
        """
        head_width = 0.05
        head_length = 0.1
        fc = 'k'
        ec = 'k'

        self.axes.arrrow(start_x, start_y, stop_x, stop_y, head_width,
                         head_length, fc, ec)

    def add_plot_1d(self,
                    wkspname,
                    wkspindex,
                    color=None,
                    label="",
                    x_label=None,
                    y_label=None,
                    marker=None,
                    line_style=None,
                    line_width=1,
                    alpha=1.,
                    show_legend=True,
                    plotError=False):

        # process inputs and defaults
        if color is None:
            color = (0, 1, 0, 1)
        if marker is None:
            marker = 'None'
        if line_style is None:
            line_style = '-'

        # color must be RGBA (4-tuple)
        wksp = addie.utilities.workspaces.get_ws(wkspname)
        if plotError:
            r = self.axes.errorbar(wksp,
                                   wkspIndex=wkspindex,
                                   color=color,
                                   marker=marker,
                                   linestyle=line_style,
                                   label=label,
                                   linewidth=line_width,
                                   alpha=alpha,
                                   markersize=40)
        else:
            # return: list of matplotlib.lines.Line2D object
            r = self.axes.plot(wksp,
                               wkspIndex=wkspindex,
                               color=color,
                               marker=marker,
                               markersize=2,
                               linestyle=line_style,
                               label=label,
                               linewidth=line_width,
                               alpha=alpha,
                               distribution=True)

        self.axes.set_aspect('auto')

        # set x-axis and y-axis label
        if x_label is not None:
            self.axes.set_xlabel(x_label, fontsize=20)
        if y_label is not None:
            self.axes.set_ylabel(y_label, fontsize=20)

        # set/update legend
        if show_legend:
            self._setup_legend()

        # Register
        line_key = self._lineIndex
        if len(r) == 1:
            self._lineDict[line_key] = r[0]
            self._lineIndex += 1
        else:
            msg = 'Return from plot is a %d-tuple: %s.. \n' % (len(r), r)
            for i_r in range(len(r)):
                msg += 'r[%d] = %s\n' % (i_r, str(r[i_r]))
            raise NotImplementedError(msg)

        # Flush/commit
        self.draw()

        return line_key

    def addPlot2D(self,
                  array2d,
                  xmin,
                  xmax,
                  ymin,
                  ymax,
                  holdprev,
                  yticklabels=None):
        """ Add a 2D plot

        Arguments:
         - yticklabels :: list of string for y ticks
        """
        # Release the current image
        self.axes.hold(holdprev)

        # Do plot
        # y ticks will be shown on line 1, 4, 23, 24 and 30
        # yticks = [1, 4, 23, 24, 30]
        # self.axes.set_yticks(yticks)

        # show image
        imgplot = self.axes.imshow(array2d,
                                   extent=[xmin, xmax, ymin, ymax],
                                   interpolation='none')
        # set y ticks as an option:
        if yticklabels is not None:
            # it will always label the first N ticks even image is zoomed in
            print(
                "--------> [FixMe]: The way to set up the Y-axis ticks is wrong!"
            )
            # self.axes.set_yticklabels(yticklabels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        # Flush...
        self._flush()

    def add_contour_plot(self, vec_x, vec_y, matrix_z):
        # create mesh grid
        grid_x, grid_y = np.meshgrid(vec_x, vec_y)

        # check size
        assert grid_x.shape == matrix_z.shape, 'Size of X (%d) and Y (%d) must match size of Z (%s).' \
                                               '' % (len(vec_x), len(vec_y), matrix_z.shape)

        # Release the current image
        self.axes.hold(False)

        # Do plot
        contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100)

        labels = [item.get_text() for item in self.axes.get_yticklabels()]
        print('[DB...BAT] Number of Y labels = ', len(labels),
              ', Number of Y = ', len(vec_y))

        # TODO/ISSUE/55: how to make this part more powerful
        if len(labels) == 2 * len(vec_y) - 1:
            new_labels = [''] * len(labels)
            for i in range(len(vec_y)):
                new_labels[i * 2] = '%d' % int(vec_y[i])
            self.axes.set_yticklabels(new_labels)

        # explicitly set aspect ratio of the image
        self.axes.set_aspect('auto')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            contour_plot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(contour_plot)
        else:
            self._colorBar.update_bruteforce(contour_plot)

        # Flush...
        self._flush()

    def addImage(self, imagefilename):
        """ Add an image by file
        """
        #import matplotlib.image as mpimg

        # set aspect to auto mode
        self.axes.set_aspect('auto')

        img = matplotlib.image.imread(str(imagefilename))
        # lum_img = img[:,:,0]
        # FUTURE : refactor for image size, interpolation and origin
        imgplot = self.axes.imshow(img,
                                   extent=[0, 1000, 800, 0],
                                   interpolation='none',
                                   origin='lower')

        # Set color bar.  plt.colorbar() does not work!
        if self._colorBar is None:
            # set color map type
            imgplot.set_cmap('spectral')
            self._colorBar = self.fig.colorbar(imgplot)
        else:
            self._colorBar.update_bruteforce(imgplot)

        self._flush()

    def clear_all_1d_plots(self):
        """ Remove all lines from the canvas
        """
        for ikey in list(self._lineDict.keys()):
            plot = self._lineDict[ikey]
            if plot is None:
                continue
            if isinstance(plot, tuple) is False:
                try:
                    self.axes.lines.remove(plot)
                except ValueError as e:
                    print(
                        "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s"
                        % (str(plot), len(self.axes.lines), str(e)))
                del self._lineDict[ikey]
            else:
                # error bar
                plot[0].remove()
                for line in plot[1]:
                    line.remove()
                for line in plot[2]:
                    line.remove()
                del self._lineDict[ikey]
            # ENDIF(plot)
        # ENDFOR

        self._setup_legend()

        self.draw()

    def clear_canvas(self):
        """ Clear data including lines and image from canvas
        """
        # clear the image for next operation
        self.axes.hold(False)

        # Clear all lines
        self.clear_all_1d_plots()

        # clear image
        self.axes.cla()
        # Try to clear the color bar
        if len(self.fig.axes) > 1:
            self.fig.delaxes(self.fig.axes[1])
            self._colorBar = None
            # This clears the space claimed by color bar but destroys sub_plot
            # too.
            self.fig.clear()
            # Re-create subplot
            self.axes = self.fig.add_subplot(111)
            self.fig.subplots_adjust(bottom=0.15)

        # flush/commit
        self._flush()

    def decrease_legend_font_size(self):
        """
        reset the legend with the new font size
        Returns:

        """
        # minimum legend font size is 2! return if it already uses the smallest
        # font size.
        if self._legendFontSize <= 2:
            return

        self._legendFontSize -= 1
        self._setup_legend()

        self.draw()

    def getLastPlotIndexKey(self):
        """ Get the index/key of the last added line
        """
        return self._lineIndex - 1

    def getPlot(self):
        """ reture figure's axes to expose the matplotlib figure to PyQt client
        """
        return self.axes

    def getXLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_xlim()

    def getYLimit(self):
        """ Get limit of Y-axis
        """
        return self.axes.get_ylim()

    def hide_legend(self):
        """
        hide the legend if it is not None
        """
        if self.axes.legend() is not None:
            # set visible to be False and re-draw
            self.axes.legend().set_visible(False)
            self.draw()

        self._isLegendOn = False

    def increase_legend_font_size(self):
        """
        reset the legend with the new font size
        """
        self._legendFontSize += 1

        self._setup_legend()

        self.draw()

    def setXYLimit(self, xmin, xmax, ymin, ymax):
        # for X
        xlims = self.axes.get_xlim()
        xlims = list(xlims)
        if xmin is not None:
            xlims[0] = xmin
        if xmax is not None:
            xlims[1] = xmax
        self.axes.set_xlim(xlims)

        # for Y
        ylims = self.axes.get_ylim()
        ylims = list(ylims)
        if ymin is not None:
            ylims[0] = ymin
        if ymax is not None:
            ylims[1] = ymax
        self.axes.set_ylim(ylims)

        # try draw
        self.draw()

    def set_title(self, title, color):
        # TODO/NOW - doc & etc

        self.axes.set_title(title, loc='center', color=color)

        self.draw()

    def remove_plot_1d(self, plot_key):
        """ Remove the line with its index as key
        """
        # Get all lines in list
        lines = self.axes.lines
        assert isinstance(lines, list), 'Lines must be list'

        if plot_key in self._lineDict:
            try:
                self.axes.lines.remove(self._lineDict[plot_key])
            except ValueError as r_error:
                error_message = 'Unable to remove to 1D line %s (ID=%d) due to %s.' % (
                    str(self._lineDict[plot_key]), plot_key, str(r_error))
                raise RuntimeError(error_message)
            # remove the plot key from dictionary
            del self._lineDict[plot_key]
        else:
            raise RuntimeError('Line with ID %s is not recorded.' % plot_key)

        self._setup_legend()

        # Draw
        self.draw()

    def show_legend(self):
        """
        show the legend if the legend is not None
        Returns:

        """
        if self.axes.legend() is not None:
            # set visible to be True and re-draw
            # self.axes.legend().set_visible(True)
            self._setup_legend()
            self.draw()

            # set flag on
            self._isLegendOn = True

    def updateLine(self,
                   ikey=-1,
                   wkspname=None,
                   wkspindex=None,
                   vecx=None,
                   vecy=None,
                   linestyle=None,
                   linecolor=None,
                   marker=None,
                   markercolor=None):
        """
        Update a plot line or a series plot line
        """

        line = self._lineDict[ikey]
        if line is None:
            print('[ERROR] Line (key = %d) is None. Unable to update' % ikey)
            return

        if wkspname or (vecx and vecy):
            if wkspname:
                vecx, vecy, _ = addie.utilities.workspaces.get_ws_data(
                    wkspname, wkspindex)
            line.set_data(vecx, vecy)

        if linecolor is not None:
            line.set_color(linecolor)

        if linestyle is not None:
            line.set_linestyle(linestyle)

        if marker is not None:
            line.set_marker(marker)

        if markercolor is not None:
            line.set_markerfacecolor(markercolor)

        oldlabel = line.get_label()
        line.set_label(oldlabel)

        self._setup_legend()

        # commit
        self.draw()

    def get_data(self, line_id):
        """
        Get vecX and vecY from line object in matplotlib
        :param line_id:
        :return: 2-tuple as vector X and vector Y
        """
        # check
        if line_id not in self._lineDict:
            raise KeyError('Line ID %s does not exist.' % str(line_id))

        # get line
        line = self._lineDict[line_id]
        if line is None:
            raise RuntimeError('Line ID %s has been removed.' % line_id)

        return line.get_xdata(), line.get_ydata()

    def getLineStyleList(self):
        return LINE_STYLES

    def getLineMarkerList(self):
        return LINE_MARKERS

    def getLineBasicColorList(self):
        return BASIC_COLORS

    def getDefaultColorMarkerComboList(self):
        """ Get a list of line/marker color and marker style combination
        as default to add more and more line to plot
        """
        combo_list = list()
        num_markers = len(LINE_MARKERS)
        num_colors = len(BASIC_COLORS)

        for i in range(num_markers):
            marker = LINE_MARKERS[i]
            for j in range(num_colors):
                color = BASIC_COLORS[j]
                combo_list.append((marker, color))
            # ENDFOR (j)
        # ENDFOR(i)

        return combo_list

    def _flush(self):
        """ A dirty hack to flush the image
        """
        w, h = self.get_width_height()
        self.resize(w + 1, h)
        self.resize(w, h)

    def _setup_legend(self, location='best'):
        """
        Set up legend
        self.axes.legend(): Handler is a Line2D object. Lable maps to the line object
        """
        allowed_location_list = [
            "best", "upper right", "upper left", "lower left", "lower right",
            "right", "center left", "center right", "lower center",
            "upper center", "center"
        ]

        # Check legend location valid or not
        if location not in allowed_location_list:
            location = 'best'

        handles, labels = self.axes.get_legend_handles_labels()
        self.axes.legend(handles,
                         labels,
                         loc=location,
                         fontsize=self._legendFontSize)

        self._isLegendOn = True