示例#1
0
    def create_sliders(self, width, height):
        """Creates the sliders, label for the slider, 
           text with value of slider and the percentage sign."""
        font = QtGui.QFont()

        x_pos = [int(width * x) for x in [0.05, 0.3, 0.55]]
        y_pos = [int(height * y) for y in [0.24, 0.33, 0.80]]
        wid = [int(width * x) for x in [0.15, 0.05, 0.04]]
        hei = [int(height * y) for y in [0.09, 0.44, 0.09]]
        i = 0

        for mode in self.mode:
            font.setPixelSize(int(height * 0.07))
            exec(f"self.{mode}_power_title = QtWidgets.QLabel(self)")
            exec(f"self.{mode}_power_title.setFont(font)")
            exec(
                f"self.{mode}_power_title.setAlignment(QtCore.Qt.AlignCenter)")
            exec(
                f"self.{mode}_power_title.setText('{self.mode_nl[self.mode.index(mode)]}')"
            )
            exec(
                f"self.{mode}_power_title.setGeometry(QtCore.QRect({x_pos[i]}, {y_pos[0]},"
                f"{wid[0]}, {hei[0]}))")

            font.setPixelSize(int(height * 0.03))
            exec(f"self.{mode}_power_value = QtWidgets.QLCDNumber(self)")
            exec(
                f"self.{mode}_power_value.setGeometry({x_pos[i]}, {y_pos[2]}, {wid[0]}, {hei[2]})"
            )
            exec(f"self.{mode}_power_value.setFont(font)")
            exec(f"self.{mode}_power_value.setDigitCount(3)")
            exec(f"self.{mode}_power_value.display(0)")

            exec(f"self.{mode}_power_slider = QtWidgets.QSlider(self)")
            exec(f"self.{mode}_power_slider.setMaximum(100)")
            exec(
                f"self.{mode}_power_slider.setOrientation(QtCore.Qt.Vertical)")
            exec(
                f"self.{mode}_power_slider.setGeometry({x_pos[i]}, {y_pos[1]},"
                f"{wid[0]}, {hei[1]})")
            exec(
                f"self.{mode}_power_slider.valueChanged.connect(self.{mode}_power_value.display)"
            )
            exec(
                f"self.{mode}_power_slider.sliderReleased.connect(self.update_data_manager)"
            )

            font.setPixelSize(int(height * 0.07))
            exec(f"self.{mode}_power_symb = QtWidgets.QLabel(self)")
            exec(
                f"self.{mode}_power_symb.setGeometry({x_pos[i] + int(width * 0.125)}, {y_pos[2]},"
                f"{wid[2]}, {hei[2]})")
            exec(f"self.{mode}_power_symb.setText('%')")
            exec(f"self.{mode}_power_symb.setFont(font)")

            i += 1

        font.setPixelSize(int(height * 0.07))
        self.opslag_title = QtWidgets.QLabel(self)
        self.opslag_title.setFont(font)
        self.opslag_title.setAlignment(QtCore.Qt.AlignCenter)
        self.opslag_title.setText('Opslaan')
        fac_scale = 0.2
        self.opslag_title.setGeometry(
            QtCore.QRect(int(width * 0.8 - hei[0] * fac_scale / 2), y_pos[0],
                         wid[0] * (1 + fac_scale), hei[0]))
        self.opslag_title.setStyleSheet(
            "QLabel { color : rgba(21, 255, 0, 255); }")

        self.bijspring_title = QtWidgets.QLabel(self)
        self.bijspring_title.setFont(font)
        self.bijspring_title.setAlignment(QtCore.Qt.AlignCenter)
        self.bijspring_title.setText('Verbruiken')
        self.bijspring_title.setGeometry(
            QtCore.QRect(int(width * 0.8 - hei[0] * fac_scale / 2), y_pos[2],
                         wid[0] * (1 + fac_scale), hei[0]))
        self.bijspring_title.setStyleSheet("QLabel {color : red; }")
        font.setPixelSize(int(height * 0.03))

        overhead3 = GraphicsLayoutWidget(self)
        overhead3.setGeometry(
            QtCore.QRect(int(width * 0.85), int(y_pos[1] + +0.49 * hei[1]),
                         int(width * 0.05), int(0.02 * hei[1])))
        overhead3.setBackground('w')

        self.h2_slide = QtWidgets.QSlider(self)
        self.h2_slide.setRange(-100, 100)
        self.h2_slide.setOrientation(QtCore.Qt.Vertical)
        self.h2_slide.setGeometry(int(width * 0.8), y_pos[1], wid[0], hei[1])
        self.h2_slide.setStyleSheet(
            """QSlider {background-color: rgba(255, 255, 255, 0)}
              QSlider::handle:vertical {
                                background: black;
                                margin: 0 -80px;
                                border: 1px solid;
                                height: 10px;
                                     }
              QSlider::groove:vertical {
                                background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0             
                                                         green, stop:1 
                                                         red);
                                width: 10px;
                                margin: 0 -5px;
                                
                                     }    """)
        overhead = GraphicsLayoutWidget(self)
        overhead.setGeometry(
            QtCore.QRect(int(width * 0.8), y_pos[1], wid[0], hei[1]))
        overhead.setBackground(None)
        overhead2 = overhead.addViewBox(enableMouse=False)
        overhead2.setBackgroundColor(None)
        overhead2.setAutoPan(False, False)

        self.data_manager.h2_slide = self.h2_slide
示例#2
0
class widget_fc_cup( QWidget ) :

	#-----------------------------------------------------------------------
	# DEFINE THE INITIALIZATION FUNCTION.
	#-----------------------------------------------------------------------

	def __init__( self, core, cup,
	              n_plt_x=None, n_plt_y=None, n_plt=None ) :

		# Inherit all attributes of an instance of "QWidget".

		super( widget_fc_cup, self ).__init__( )

		# Initialize the counter of repaint events for this widget as
		# well as a maximum value for this counter.

		# Note.  For some reason, adjusting the individual plots to have
		#        uniform sizes is difficult to achieve before the widget
		#        is rendered.  Thus, once a paint event occurs, the
		#        "self.paintEvent( )" function picks it up and makes a
		#        call to "self.ajst_grd( )".  This counter and its
		#        maximum value are used ensure that "self.paintEvent( )"
		#        makes such a call only in response to the intial few
		#        painting (so as to prevent an infinite loop).

		# Note.  The first paint seems to be a "dummy" of some sort.
		#        Whatever the case, "self.n_paint_max = 1" seems to
		#        generally be insufficient.

		self.n_painted     = 0
		self.n_painted_max = 3

		# Store the Janus core and the cup number.

		# Note.  The cups are traditionally numbered "1" and "2", but,
		#        in this class, they are identified by the altitude
		#        index "t" which takes the values "0" and "1",
		#        respectively.

		self.core = core

		self.c = None
		self.c = 0 if ( cup == 1 ) else self.c
		self.c = 1 if ( cup == 2 ) else self.c

		# Prepare to respond to signals received from the Janus core.

		self.connect( self.core, SIGNAL('janus_rset'), self.resp_rset )
		self.connect( self.core, SIGNAL('janus_chng_spc'),
		                                            self.resp_chng_spc )
		self.connect( self.core, SIGNAL('janus_chng_mom_sel_bin'),
		                                    self.resp_chng_mom_sel_bin )
		self.connect( self.core, SIGNAL('janus_chng_mom_sel_dir'),
		                                    self.resp_chng_mom_sel_dir )
		self.connect( self.core, SIGNAL('janus_chng_mom_sel_all'),
		                                    self.resp_chng_mom_sel_all )
		self.connect( self.core, SIGNAL('janus_chng_mom_res'),
		                                        self.resp_chng_mom_res )
		self.connect( self.core, SIGNAL('janus_chng_nln_gss'),
		                                        self.resp_chng_nln_gss )
		self.connect( self.core, SIGNAL('janus_chng_nln_sel_bin'),
		                                    self.resp_chng_nln_sel_bin )
		self.connect( self.core, SIGNAL('janus_chng_nln_sel_all'),
		                                    self.resp_chng_nln_sel_all )
		self.connect( self.core, SIGNAL('janus_chng_nln_res'),
		                                        self.resp_chng_nln_res )
		self.connect( self.core, SIGNAL('janus_chng_dsp'),
		                                            self.resp_chng_dsp )

		# Assign (if not done so already) and store the shape of the
		# plot-grid array.

		self.n_plt_x = 4 if ( n_plt_x is None ) else n_plt_x
		self.n_plt_y = 5 if ( n_plt_y is None ) else n_plt_y

		if ( n_plt is None ) :
			self.n_plt = self.n_plt_x * self.n_plt_y

		# Initizalize the pens, brushes, and fonts used by this widget.

		self.pen_plt   = mkPen( color='k' )
		self.pen_hst   = mkPen( color='k' )
		self.pen_pnt_c = mkPen( color='k' )
		self.pen_pnt_y = mkPen( color='k' )
		self.pen_pnt_r = mkPen( color='k' )
		self.pen_crv_b = mkPen( color='b' )
		self.pen_crv_g = mkPen( color='g' )

		self.bsh_pnt_c = mkBrush( color='c' )
		self.bsh_pnt_y = mkBrush( color='y' )
		self.bsh_pnt_r = mkBrush( color='r' )

		self.fnt = self.core.app.font( )

		# Set the maximum number of velocity channels and the maximum
		# number of ion species.

		self.n_k   = 31
		self.n_ion = self.core.nln_n_pop

		# Initialize the widget and it's plot's.

		self.init_plt( )

		# Populate the plots with the histograms (and labels), the
		# selection points, and the fit curves.

		self.make_hst( )
		self.make_pnt( )
		self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR INITIALIZING THE WIDGET AND ITS PLOTS.
	#-----------------------------------------------------------------------

	def init_plt( self ) :

		# Initialize the "GraphicsLayoutWidget" for this widget.  This
		# will allow a grid of "GraphicsItem" objects, which will
		# include the plots themselves, the axes, and the axis labels.

		# Note.  The "QGridLayout" object given to this widget as its
		#        layout is essentially a dummy.  I tried to just having
		#        this widget be an extention of "GraphicsLayoutWidget"
		#        (i.e., having it inheret that type), but I couldn't get
		#        it to display anything at all.

		self.setLayout( QGridLayout( ) )

		self.grd = GraphicsLayoutWidget( )
		self.grd.setBackground( 'w' )
		self.layout( ).addWidget( self.grd )

		self.layout().setContentsMargins( 0, 0, 0, 0 )

		# Initialize the text for the x- and y-axis labels.  Then,
		# create the labels themselves and add them to the grid.

		self.txt_axs_x = 'Projected Proton Inflow Velocity [km/s]'
		self.txt_axs_y = 'Current [pA]'

		if ( self.core.app.res_lo ) :
			size =  '8pt'
		else :
			size = '10pt'

		self.lab_axs_x = LabelItem( self.txt_axs_x, angle=0  ,
		                            color='b', size=size       )
		self.lab_axs_y = LabelItem( self.txt_axs_y, angle=270, 
		                            color='b', size=size       )

		self.grd.addItem( self.lab_axs_x, self.n_plt_y + 1, 2,
		                                  1, self.n_plt_x      )
		self.grd.addItem( self.lab_axs_y, 0, 0,
		                                  self.n_plt_y, 1      )

		# Initialize the arrays that will contain the individual axes,
		# plots, and plot elements (i.e., the histograms, fit curves,
		# labels, and selection points).

		self.plt = tile( None, [ self.n_plt_y, self.n_plt_x ] )

		self.axs_x = tile( None, self.n_plt_x )
		self.axs_y = tile( None, self.n_plt_y )

		self.hst = tile( None, [ self.n_plt_y, self.n_plt_x ] )
		self.lbl = tile( None, [ self.n_plt_y, self.n_plt_x ] )

		self.crv     = tile( None, [ self.n_plt_y, self.n_plt_x ] )
		self.crv_ion = tile( None, [ self.n_plt_y, self.n_plt_x,
		                             self.n_ion                  ] )

		self.pnt = tile( None, [ self.n_plt_y, self.n_plt_x, 
		                         self.n_k                    ] )

		# Initialize the scale-type for each axis, then generate the
		# (default) axis-limits and adjusted axis-limits.

		self.log_x = False
		self.log_y = True

		self.make_lim( )

		# Create, store, and add to the grid the individual axes: first
		# the horizontal and then the vertical.

		for i in range( self.n_plt_x ) :

			self.axs_x[i] = AxisItem( 'bottom', maxTickLength=5 )
			self.axs_x[i].setLogMode( self.log_x )
			self.axs_x[i].setRange( self.alm_x[0], self.alm_x[1] )
			self.axs_x[i].setTickFont( self.fnt )

			if ( self.core.app.res_lo ) :
				self.axs_x[i].setHeight( 10 )
			else :
				self.axs_x[i].setHeight( 20 )

			self.grd.addItem( self.axs_x[i], self.n_plt_y, i + 2 )

		for j in range( self.n_plt_y ) :

			self.axs_y[j] = AxisItem( 'left', maxTickLength=5 )
			self.axs_y[j].setLogMode( self.log_y )
			self.axs_y[j].setRange( self.alm_y[0], self.alm_y[1] )
			self.axs_y[j].setTickFont( self.fnt )

			if ( self.core.app.res_lo ) :
				self.axs_y[j].setWidth( 32 )
			else :
				self.axs_y[j].setWidth( 40 )

			self.grd.addItem( self.axs_y[j], j, 1 )

		# Create, store, and add to the grid the individual plots.
		# Likewise, create, store, and add to each plot a label.

		for j in range( self.n_plt_y ) :

			for i in range( self.n_plt_x ) :

				# Compute the plot number of this plot.

				d = self.calc_ind_d( j, i )


				# If creating this plot would exceed the
				# specified number of plots, don't create it.

				if ( d >= self.n_plt ) :
					continue

				# Create and store this plot, adjust its limits,
				# and add it to the grid.

				self.plt[j,i] = event_ViewBox( self,
				                          border=self.pen_plt,
				                          enableMouse=False,
				                          enableMenu=False     )

				self.plt[j,i].setRange( xRange=self.alm_x,
				                        yRange=self.alm_y,
				                        padding=0.         )

				self.grd.addItem( self.plt[j,i], j, i + 2 )

				# Create and store an (empty) label and add it
				# to this plot.

				self.lbl[j,i] = TextItem( anchor=(1,0) )

				self.lbl[j,i].setFont( self.fnt )

				self.plt[j,i].addItem( self.lbl[j,i] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR GENERATING AXIS-LIMITS (AND ADJUSTED LIMITS).
	#-----------------------------------------------------------------------

	def make_lim( self ) :

		# If no spectrum has been loaded, use the default limits;
		# otherwise, use the spectral data to compute axis limits.

		if ( self.core.fc_spec is None ) :

			self.lim_x = [ 250. , 750. ]
			self.lim_y = [   0.7,  70. ]

		else :

			self.lim_x = [self.core.fc_spec['vel_strt'][self.c][0 ],
			              self.core.fc_spec['vel_stop'][self.c][-1]]

			arr_curr_flat = self.core.fc_spec['curr_flat']

			self.lim_y = [ min(arr_curr_flat), max(arr_curr_flat)  ]

			if ( self.log_y ) :
				self.lim_y[1] = self.lim_y[1] ** 1.1
			else :
				self.lim_y[1] += 0.1 * ( self.lim_y[1] -
				                         self.lim_y[0]   )

		# Compute the "adjusted limits" for each axis.

		if ( self.log_x ) :
			self.alm_x = [ log10( x ) for x in self.lim_x ]
		else :
			self.alm_x = self.lim_x

		if ( self.log_y ) :
			self.alm_y = [ log10( y ) for y in self.lim_y ]
		else :
			self.alm_y = self.lim_y

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CREATING THE PLOTS' HISTOGRAMS (AND LABELS).
	#-----------------------------------------------------------------------

	def make_hst( self, curr_min=0.69 ) :

		# If no spectrum has been loaded, clear any existing histograms
		# and abort.

		if ( self.core.fc_spec is None ) :

			self.rset_hst( )

			return

		# Use the spectral data to compute new axis-limits.

		self.make_lim( )

		# Generate a step function for each look direction associated
		# with this widget.

		self.stp = array( [ step(  self.core.fc_spec['vel_cen'][self.c] ,
					   self.core.fc_spec['vel_del'][self.c] ,
					   self.core.fc_spec['curr'][self.c][d])
						for d in range(self.core.fc_spec['n_dir']) ])

		stp_pnt = array( [ array( self.stp[d]\
		                              .calc_pnt( lev_min=curr_min ) )
		                for d in range( self.core.fc_spec['n_dir'] ) ] )

		self.stp_x = stp_pnt[:,0,:]
		self.stp_y = stp_pnt[:,1,:]

		self.asp_x = log10( self.stp_x ) if ( self.log_x ) else \
		                    self.stp_x
		self.asp_y = log10( self.stp_y ) if ( self.log_y ) else \
		                    self.stp_y

		# Adjust the individual axes to the new limits.

		for i in range( self.n_plt_x ) :
			self.axs_x[i].setRange( self.alm_x[0], self.alm_x[1] )

		for j in range( self.n_plt_y ) :
			self.axs_y[j].setRange( self.alm_y[0], self.alm_y[1] )

		# For each plot in the grid, adjust its limits, add a histogram,
		# and add a direction label.

		for d in range( min( self.core.fc_spec['n_dir'], self.n_plt ) ) :

			# Determine the location of this plot within the grid
			# layout.

			j = self.calc_ind_j( d )
			i = self.calc_ind_i( d )

			# If this plot does not exist, move onto the next one.

			if ( self.plt[j,i] is None ) :
				continue

			# If a histogram already exists for this plot, remove
			# and delete it.

			if ( self.hst[j,i] is not None ) :
				self.plt[j,i].removeItem( self.hst[j,i] )
				self.hst[j,i] = None

			# Clear this plot's label of text.

			self.lbl[j,i].setText( '' )

			# Adjust this plot's limits and then move it's label in
			# response.

			self.plt[j,i].setRange( xRange=self.alm_x,
			                        yRange=self.alm_y,
			                        padding=0.         )

			self.lbl[j,i].setPos( self.alm_x[1], self.alm_y[1] )

			# Update this plot's label with appropriate text
			# indicating the pointing direction.

			r_alt = round( self.core.fc_spec['elev'][self.c] )
			r_dir = round( self.core.fc_spec['azim'][self.c][d])

			txt = ( u'({0:+.0f}\N{DEGREE SIGN}, ' + 
			        u'{1:+.0f}\N{DEGREE SIGN})'     ).format(
			                                          r_alt, r_dir )

			self.lbl[j,i].setText( txt, color=(0,0,0) )
			#self.lbl[j,i].setFont( self.fnt           )

			# Generate the histogram for the data from this look
			# direction and display it in the plot.

			self.hst[j,i] = PlotDataItem( self.asp_x[d,:],
			                              self.asp_y[d,:],
			                              pen=self.pen_hst )

			self.plt[j,i].addItem( self.hst[j,i] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CREATING THE PLOTS' SELECTION POINTS.
	#-----------------------------------------------------------------------

	def make_pnt( self, curr_min=0.69 ) :

		# Add selection points to each plot.

		if ( self.core.fc_spec is None ) :

			return

		# Add selection points to each plot.

		for d in range( min( self.core.fc_spec['n_dir'], self.n_plt ) ) :

			# Determine the location of this plot within the grid
			# layout.

			j = self.calc_ind_j( d )
			i = self.calc_ind_i( d )

			# If this plot does not exist, move onto the next one.

			if ( self.plt[j,i] is None ) :
				continue

			# Add the selection points to this plot.

			for b in range( self.core.fc_spec['n_bin'] ) :

				sel_bin = False
				sel_dir = True
				sel_alt = None

				if ( ( self.core.dsp == 'mom'          ) and 
				     ( self.core.mom_sel_bin
						           is not None ) and
				     ( self.core.mom_sel_dir
					                   is not None )     ) :

					sel_bin = \
					       self.core.mom_sel_bin[self.c][d][b]
					sel_dir = \
					       self.core.mom_sel_dir[self.c][d]

				elif ( ( self.core.dsp == 'gsl'        ) and 
				       ( self.core.nln_sel is not None )     ) :

					sel_bin = self.core.nln_sel[self.c][d][b]

				elif ( ( self.core.dsp == 'nln'        ) and 
				       ( self.core.nln_res_sel
					                   is not None )     ) :

					sel_bin = \
					       self.core.nln_res_sel[self.c][d][b]

					if ( self.core.nln_sel is None ) :
						sel_alt = None
					else :
						sel_alt = \
						   self.core.nln_sel[self.c][d][b]

				self.chng_pnt( j, i, b, sel_bin,
					       sel_dir=sel_dir,
					       sel_alt=sel_alt   )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CREATING THE PLOTS' FIT CURVES.
	#-----------------------------------------------------------------------

	def make_crv( self, d_lst=None ) :

		# If no "list" of "p" index-values has been provided by the
		# user, assume that the curves in all plots should be
		# (re-)rendered.

		if ( self.core.fc_spec is None ) :
			return

		if ( d_lst is None ) :
			d_lst = range( min( self.core.fc_spec['n_dir'],
			               self.n_plt                       ) )

		# If the results of the analysis are missing, abort; otherwise,
		# extract the current values to be plotted.

		if ( self.core.dsp == 'mom' ) :
			curr     = self.core.mom_curr
			curr_ion = None
		elif ( self.core.dsp == 'gsl' ) :
			curr     = self.core.nln_gss_curr_tot
			curr_ion = self.core.nln_gss_curr_ion
		elif ( self.core.dsp == 'nln' ) :
			curr     = self.core.nln_res_curr_tot
			curr_ion = self.core.nln_res_curr_ion
		else :
			curr     = None
			curr_ion = None

		# For each plot in the grid, generate and display a fit curve
		# based on the results of the analysis.

		vel_cen = self.core.fc_spec['vel_cen'][self.c]

		for d in d_lst :

			# Determine the location of this plot within the grid
			# layout.

			j = self.calc_ind_j( d )
			i = self.calc_ind_i( d )

			# If this plot does not exist, move onto the next grid
			# element.

			if ( self.plt[j,i] is None ) :
				continue

			# If any curves already exist for this plot, remove and
			# delete them.

			if ( self.crv[j,i] is not None ) :
				self.plt[j,i].removeItem( self.crv[j,i] )
				self.crv[j,i] = None

			for n in range( self.n_ion ) :
				if ( self.crv_ion[j,i,n] is not None ) :
					self.plt[j,i].removeItem(
					                   self.crv_ion[j,i,n] )
					self.crv_ion[j,i,n] = None

			# Create and add the curve of the individual
			# contributions to the modeled current to the plot.

			if ( curr_ion is not None ) :

				for n in range( len( curr_ion[self.c][d][0] ) ) :

					# Extract the points for this fit curve.

					x = array( vel_cen )
					y = array( [ curr_ion[self.c][d][b][n]
					      for b in range(
					        self.core.fc_spec['n_bin'] ) ] )

					# Select only those points for which
					# the fit current is strictly positive.

					tk = where( y > 0. )[0]

					# If fewer than two curve points were
					# selected, skip plotting this curve.

					if ( len( tk ) < 2 ) :
						continue

					# Generate the adjusted points for this
					# curve.

					if ( self.log_x ) :
						ax = log10( x[tk] )
					else :
						ax = x[tk]

					if ( self.log_y ) :
						ay = log10( y[tk] )
					else :
						ay = y[tk]

					# Create, store, and add to the plot
					# this fit curve.

					self.crv_ion[j,i,n] = PlotDataItem(
					            ax, ay, pen=self.pen_crv_g )

					self.plt[j,i].addItem(
					                   self.crv_ion[j,i,n] )

			# Create, store, and add to the plot a curve for the
			# total fit current.

			if ( curr is not None ) :

				# Extract the points of the fit curve.

				x = [ self.core.fc_spec.arr[self.c][0][b][
				                                    'vel_cen']
				      for b in range(
				                  self.core.fc_spec['n_bin'] ) ]

				y = curr[self.c][d]

				x = array( x )
				y = array( y )

				# Select only those points for which the fit
				# current is strictly positive.

				valid = [ yy > 0. for yy in y ]

				n_a = sum( valid )

				ax = [ xx for xx, vv in zip( x, valid ) if vv ]
				ay = [ yy for yy, vv in zip( y, valid ) if vv ]

				# If at least two points were selected, proceed
				# with plotting.

				if ( n_a >= 2 ) :

					# If needed, convert to a logarithmic
					# scale.

					if ( self.log_x ) :
						ax = [ log10( xx )
						       for xx in ax ]
					if ( self.log_y ) :
						ay = [ log10( yy )
					               for yy in ay ]

					# Create, store, and add to the plot
					# this fit curve.

					self.crv[j,i] = PlotDataItem(
					            ax, ay, pen=self.pen_crv_b )

					self.plt[j,i].addItem( self.crv[j,i] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CHANGING THE VISIBILITY OF A DATUM'S POINTS.
	#-----------------------------------------------------------------------

	def chng_pnt( self, j, i, b, sel_bin,
	              sel_dir=True, sel_alt=None ) :

		# If this point already exists, remove it from its plot and
		# delete it.

		if ( self.pnt[j,i,b] is not None ) :
			self.plt[j,i].removeItem( self.pnt[j,i,b] )
			self.pnt[j,i,b] = None

		# If the user gave no alternative selection state for this
		# datum, use the primary state for the secondary state.

		sel_alt = sel_bin if ( sel_alt is None ) else sel_alt

		# If this point was not selected (based on both its primary and
		# secondary states), return (since there's nothing more to be
		# done).

		if ( ( not sel_bin ) and ( not sel_alt ) ) :
			return

		# Determine the "d" index corresponding to this look direction.

		d = self.calc_ind_d( j, i )

		# Computed the adjusted point location in the "ViewBox".

		if ( self.log_x ) :
			ax = log10( self.core.fc_spec['vel_cen'][self.c][b] )
		else :
			ax = self.core.fc_spec['vel_cen'][self.c][b]
		if ( self.log_y ) :
			ay = log10( self.core.fc_spec['curr'][self.c][d][b] )
		else :
			ay = self.core.fc_spec['curr'][self.c][d][b]

		# Select the color for the point (i.e., the brush and pen used
		# to render it) based on whether or not this datum's look
		# direction has been selected and whether or not the primary and
		# secondary selection states match.

		if ( sel_dir ) :
			if ( sel_bin == sel_alt ) :
				pen   = self.pen_pnt_c
				brush = self.bsh_pnt_c
			else :
				pen   = self.pen_pnt_y
				brush = self.bsh_pnt_y
		else :
			pen   = self.pen_pnt_r
			brush = self.bsh_pnt_r

		# Select the symbol based on the values of the primary and
		# secondary selection states.

		# Note.  At this point in the code, at least one of these two
		#        states must be "True" since this -- when both states
		#        are "False", this function returns before it reaches
		#        this point.

		if ( sel_bin ) :
			if ( sel_alt ) :
				symbol = 's'
			else :
				symbol = 'o'
		else :
			symbol = 't'

		# Create, store, and add this selection point to the plot.

		if ( self.core.app.res_lo ) :
			size = 3
		else :
			size = 6

		self.pnt[j,i,b] = PlotDataItem( [ax], [ay],
		                                symbol=symbol,
		                                symbolSize=size,
		                                symbolPen=pen,
		                                symbolBrush=brush )

		self.plt[j,i].addItem( self.pnt[j,i,b] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESETTING THE PLOTS' HISTOGRAMS (AND LABELS).
	#-----------------------------------------------------------------------

	def rset_hst( self, rset_lbl=False ) :

		# For each plot that exists in the grid, remove and delete it's
		# histogram.  Likewise, if requested, empty it's label (but
		# still leave the label itself intact).

		for j in range( self.n_plt_y ) :

			for i in range( self.n_plt_x ) :

				# If the plot does not exist, move onto the the
				# next one.

				if ( self.plt[j,i] is None ) :
					continue

				# If a histogram exists for this plot, remove
				# and delete it.

				if ( self.hst[j,i] is not None ) :
					self.plt[j,i].removeItem(
					                         self.hst[j,i] )
					self.hst[j,i] = None

				# If requested, reset this plot's label text to
				# the empty string.

				if ( rset_lbl ) :
					self.lbl[j,i].setText( '',
					                       color=(0,0,0) )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESETTING THE PLOTS' SELECTION POINTS.
	#-----------------------------------------------------------------------

	def rset_pnt( self ) :

		# For each plot that exists in the grid, hide and remove its
		# selection points.

		for j in range( self.n_plt_y ) :

			for i in range( self.n_plt_x ) :

				# If the plot does not exist, move onto the the
				# next grid element.

				if ( self.plt[j,i] is None ) :
					continue

				# Remove and then delete each of this plot's
				# selection points.

				for b in range( self.n_k ) :
					if ( self.pnt[j,i,b] is not None ) :
						self.plt[j,i].removeItem(
						               self.pnt[j,i,b] )
						self.pnt[j,i,b] = None

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESETTING THE PLOTS' FIT CURVES.
	#-----------------------------------------------------------------------

	def rset_crv( self ) :

		# For each plot that exists in the grid, remove and delete its
		# fit curves.

		for j in range( self.n_plt_y ) :

			for i in range( self.n_plt_x ) :

				# If the plot does not exist, move onto the the
				# next one.

				if ( self.plt[j,i] is None ) :
					continue

				# Remove and delete this plot's fit curve.

				if ( self.crv[j,i] is not None ) :
					self.plt[j,i].removeItem(
					                         self.crv[j,i] )
					self.crv[j,i] = None

				for n in range( self.n_ion ) :

					if ( self.crv_ion[j,i,n] is not None ) :
						self.plt[j,i].removeItem(
						           self.crv_ion[j,i,n] )
						self.crv_ion[j,i,n] = None

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION CALCULATING THE INDEX "i" FROM THE INDEX "d".
	#-----------------------------------------------------------------------

	def calc_ind_i( self, d ) :

		# Return the index "i" (i.e., column in the grid of plots)
		# corresponding to the index "d" (i.e., look direction value)
		# passed by the user.

		return d % self.n_plt_x

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION CALCULATING THE INDEX "j" FROM THE INDEX "d".
	#-----------------------------------------------------------------------

	def calc_ind_j( self, d ) :

		# Return the index "j" (i.e., row in the grid of plots)
		# corresponding to the index "d" (i.e., look direction value)
		# passed by the user.

                return int( floor( d / ( 1. * self.n_plt_x ) ) )
	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION CALCULATING INDEX "d" FROM INDICES "j" AND "i".
	#-----------------------------------------------------------------------

	def calc_ind_d( self, j, i ) :

		# Return the index "d" (i.e., look direction value) 
		# corresponding to the indices "j" and "i" (i.e., location in 
		# the grid of plots) passed by the user.

		return i + ( j * self.n_plt_x )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO A USER-INITIATED EVENT.
	#-----------------------------------------------------------------------

	def user_event( self, event, plt_ji ) :

		# If a "thread_*" computation thread is already running, abort.

		if ( n_thread( ) != 0 ) :

			return

		# If no spectrum has been loaded, abort.

		if ( ( self.core.fc_spec is None       ) or
		     ( self.core.fc_spec['n_bin'] <= 0 )    ) :

			return

		# Extract the location of the plot in the grid.

		tk = where( self.plt == plt_ji )

		j = tk[0][0]
		i = tk[1][0]

		# Determine the look direction corresponding to this plot.

		d = self.calc_ind_d( j, i )

		# Extract the data shown in this plot.  Convert them first to
		# their adjusted values, and then to their equivalent pixel
		# positions in the "ViewBox".

		dat_x = self.core.fc_spec['vel_cen'][self.c]
		dat_y = self.core.fc_spec['curr'][self.c][d]

		dat_ax = log10( dat_x ) if ( self.log_x ) else dat_x
		dat_ay = log10( dat_y ) if ( self.log_y ) else dat_y

		dat_a = tile( None, self.core.fc_spec['n_bin'] )

		for b in range( self.core.fc_spec['n_bin'] ) :
			dat_a[b] = QPointF( dat_ax[b], dat_ay[b] )

		dat_p = array( [
		             self.plt[j,i].mapFromView( da ) for da in dat_a ] )

		dat_px = array( [ dp.x( ) for dp in dat_p ] )
		dat_py = array( [ dp.y( ) for dp in dat_p ] )

		# Extract the pixel position of the mouse-click event.

		evt_p = event.pos( )

		evt_px = evt_p.x( )
		evt_py = evt_p.y( )

		# Compute the distance (in pixels) of each datum's location from
		# the location of the mouse-click event.  Then, identify the
		# closest datum.

		dst = sqrt( ( dat_px - evt_px )**2 + ( dat_py - evt_py )**2 )

		b = where( dst == amin( dst ) )[0][0]

		# If the distance between the nearest datum and the mouse click
		# is within a set tolerance, invert the selection of that datum
		# (i.e., de-select it if its already selected or select it if it
		# isn't selected).

		tol = 25.

		if ( dst[b] <= tol ) :

			if ( self.core.dsp == 'mom' ) :

				Thread( target=thread_chng_mom_sel,
				        args=( self.core,
				               self.c, d, b ) ).start()

			elif ( self.core.dsp == 'gsl' ) :

				Thread( target=thread_chng_nln_sel,
				        args=( self.core,
				               self.c, d, b ) ).start()

			elif ( self.core.dsp == 'nln' ) :

				Thread( target=thread_chng_nln_sel,
				        args=( self.core,
				               self.c, d, b ) ).start()

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "rset" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_rset( self ) :

		# Clear the plots of all their elements.

		self.rset_crv( )
		self.rset_pnt( )
		self.rset_hst( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_spc" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_spc( self ) :

		# Clear the plots of all their elements and regenerate them.

		self.rset_crv( )
		self.rset_pnt( )
		self.rset_hst( )

		self.make_hst( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_sel_bin" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_mom_sel_bin( self, c=None, d=None, b=None ) :

		# If one of the keyword arguments is missing, invalid, or
		# non-applicable to this widget, abort.

		if ( ( c is None ) or ( d is None ) or ( b is None ) ) :
			return

		try :
			c = int( c )
			d = int( d )
			b = int( b )
		except :
			return

		if ( c != self.c ) :
			return

		if ( ( d < 0 ) or ( d >= self.core.fc_spec['n_dir'] ) ) :
			return

		if ( ( b < 0 ) or ( b >= self.core.fc_spec['n_bin'] ) ) :
			return

		# If the results of the moments analysis are being displayed,
		# update the color and visibility of the corresponding plot
		# points based on a possible change in the selection status of
		# that datum or its pointing window.

		if ( self.core.dsp == 'mom' ) :

			# Determine the location of this plot within the grid
			# layout.

			j = self.calc_ind_j( d )
			i = self.calc_ind_i( d )

			# Update the color and visibility of the plot point
			# corresponding to the specified datum.

			self.chng_pnt( j, i, b,
			               self.core.mom_sel_bin[c][d][b],
			               sel_dir=self.core.mom_sel_dir[c][ d] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_sel_dir" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_mom_sel_dir( self, c=None, d=None ) :

		# If one of the keyword arguments is missing, invalid, or
		# non-applicable to this widget, abort.

		if ( ( c is None ) or ( d is None ) ) :
			return

		try :
			c = int( c )
			d = int( d )
		except :
			return

		if ( c != self.c ) :
			return

		if ( ( d < 0 ) or ( d >= self.core.fc_spec['n_dir'] ) ) :
			return

		# If the results of the moments analysis are being displayed and
		# the "t" value passed to this function corresponds to that for
		# this widget, update the color and visibility of the
		# corresponding plot points based on a possible change in the
		# selection status of that pointing window.

		if ( self.core.dsp == 'mom' ) :

			# Determine the location of this plot within the grid
			# layout.

			j = self.calc_ind_j( d )
			i = self.calc_ind_i( d )

			# Update the color and visibility of the plot points
			# corresponding to each of this look direction's data.

			for b in range( self.core.fc_spec['n_bin'] ) :
				self.chng_pnt( j, i, b,
				            self.core.mom_sel_bin[c][d][b],
				            sel_dir=self.core.mom_sel_dir[c][d] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_sel_all" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_mom_sel_all( self ) :

		# If the results of the moments analysis are being displayed,
		# reset any existing selection points and create new ones.

		if ( self.core.dsp == 'mom' ) :

			self.make_pnt( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_res" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_mom_res( self ) :

		# If the results of the moments analysis are being displayed,
		# reset any existing fit curves and make new ones.

		if ( self.core.dsp == 'mom' ) :

			self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_gss" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_nln_gss( self ) :

		# If the initial guess for the non-linear analysis is being
		# displayed, reset any existing fit curves and make new ones.

		if ( self.core.dsp == 'gsl' ) :

			self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_sel_bin" SIGNAL.
        #-----------------------------------------------------------------------

	def resp_chng_nln_sel_bin( self, c=None, d=None, b=None ) :

		# If one of the keyword arguments is missing, invalid, or
		# non-applicable to this widget, abort.

		if ( ( c is None ) or ( d is None ) or ( b is None ) ) :
			return

		try :
			c = int( c )
			d = int( d )
			b = int( b )
		except :
			return

		if ( c != self.c ) :
			return

		if ( ( d < 0 ) or ( d >= self.core.fc_spec['n_dir'] ) ) :
			return

		if ( ( b < 0 ) or ( b >= self.core.fc_spec['n_bin'] ) ) :
			return

		# Determine the location of this plot within the grid layout.

		j = self.calc_ind_j( d )
		i = self.calc_ind_i( d )

		# If the point selection for the non-linear analysis is being
		# displayed, update the color and visibility of the plot point
		# corresponding to the datum "[c,d,b]" based on a possible
		# change in the selection status of that datum.

		if ( self.core.dsp == 'gsl' ) :

			self.chng_pnt( j, i, b,
			               self.core.nln_sel[self.c][d][b] )

			self.make_crv( )

		elif ( self.core.dsp == 'nln' ) :

			if ( self.core.nln_res_sel is None ) :
				self.chng_pnt( j, i, b,
				              False,
				              sel_alt=self.core.nln_sel[self.c][d][b] )			
			else :
				self.chng_pnt( j, i, b,
				              self.core.nln_res_sel[self.c][d][b],
				              sel_alt=self.core.nln_sel[self.c][d][b] )

			self.make_crv( d_lst=[d] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_sel_all" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_nln_sel_all( self ) :

		# If the point selection for the non-linear analysis is being
		# displayed, reset any existing selection points and create new
		# ones.

		if ( ( self.core.dsp == 'gsl' ) or
		     ( self.core.dsp == 'nln' )    ) :

			self.make_pnt( )
			self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_res" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_nln_res( self ) :

		# If the results of the non-linear analysis are being displayed,
		# reset any existing fit curves and make new ones.

		if ( self.core.dsp == 'nln' ) :

			self.make_pnt( )
			self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_dsp" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_dsp( self ) :

		# Reset the selection points and fit curves.

		self.make_pnt( )
		self.make_crv( )
示例#3
0
文件: Scope.py 项目: yunpoyue/Python
class ScopeWindow(QtGui.QMainWindow):
    def __init__(self, parent=None, maxepisodes=10):
        super(ScopeWindow, self).__init__(parent)
        self.episodes = None
        self.index = []
        # set a limit on how many episodes to memorize
        self.maxepisodes = maxepisodes
        # Record state of the scope window
        self.isclosed = True
        # This keeps track of the indices of which episodes are loaded
        self._loaded_array = []
        # Default options
        self.options = {'colorfy':False,\
        'layout':[['Voltage', 'A', 0, 0], ['Current', 'A', 1, 0]]} # layout = [Stream, Channel, row, col]
        # Keep track of which colors have been used
        self._usedColors = []
        # Set up the GUI window
        self.setupUi(self)
        self.setDisplayTheme()

    def setupUi(self, MainWindow):
        """This function is converted from the .ui file from the designer"""
        MainWindow.setObjectName(_fromUtf8("Scope Window"))
        MainWindow.resize(1200, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))

        # Graphics layout
        self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.graphicsLayout = QtGui.QHBoxLayout()
        self.graphicsLayout.setObjectName(_fromUtf8("graphicsLayout"))
        self.graphicsView = GraphicsLayoutWidget(self.centralwidget)
        self.graphicsView.setObjectName(_fromUtf8("graphicsView"))
        self.graphicsLayout.addWidget(self.graphicsView)
        self.horizontalLayout.addLayout(self.graphicsLayout)

        # Side panel layout: initialize as a list view
        self.sideDockPanel = QtGui.QDockWidget("Settings", self)
        self.sideDockPanel.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
        self.sideDockPanel.setObjectName(_fromUtf8("sideDockPanel"))
        self.sideDockPanel.hide()
        # self.sidePanelLayout = QtGui.QHBoxLayout()
        # self.sidePanelLayout.setObjectName(_fromUtf8("sidePanelLayout"))
        self.listView = QtGui.QListView(self.centralwidget)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.listView.sizePolicy().hasHeightForWidth())
        self.listView.setSizePolicy(sizePolicy)
        self.listView.setObjectName(_fromUtf8("listView"))
        self.sideDockPanel.setWidget(self.listView)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.sideDockPanel)
        # self.sidePanelLayout.addWidget(self.listView)
        # self.horizontalLayout.addLayout(self.sidePanelLayout)
        MainWindow.setCentralWidget(self.centralwidget)

        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1225, 26))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        self.setMenuBarItems()
        MainWindow.setMenuBar(self.menubar)

        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    # ---------------- Additional main window behaviors -----------------------
    def setMenuBarItems(self):
        # File Menu
        fileMenu = self.menubar.addMenu('&File')
        # File: Export
        exportMenu = fileMenu.addMenu('&Export')
        exportWithScaleBarAction = QtGui.QAction(QtGui.QIcon('export.png'), 'Export with scalebar', self)
        exportWithScaleBarAction.setShortcut('Ctrl+Alt+E')
        exportWithScaleBarAction.setStatusTip('Export with scalebar')
        exportWithScaleBarAction.triggered.connect(self.printme)
        exportMenu.addAction(exportWithScaleBarAction)

        # View Menu
        viewMenu = self.menubar.addMenu('&View')
        # View: show settings
        viewMenu.addAction(self.sideDockPanel.toggleViewAction())
        # View: Colorfy
        colorfyAction = QtGui.QAction('Color code traces', self, checkable=True, checked=False)
        colorfyAction.setShortcut('Ctrl+Alt+C')
        colorfyAction.setStatusTip('Toggle between color coded traces and black traces')
        colorfyAction.triggered.connect(lambda: self.toggleTraceColors(colorfyAction.isChecked()))
        viewMenu.addAction(colorfyAction)

    def printme(self):
        print('doing stuff')

    def closeEvent(self, event):
        """Override default behavior when closing the main window"""
        self.isclosed = True

    def retranslateUi(self, MainWindow):
        """Set window title and other miscellaneous"""
        MainWindow.setWindowTitle(_translate(__version__, __version__, None))

    # ------------- Episode plotting utilities --------------------------------
    def updateEpisodes(self, episodes=None, index=[]):
        """First compare episodes with self.episodes and index with self.index
        Only update the difference in the two sets"""
        if not isinstance(episodes, dict) or not isinstance(self.episodes, dict):
            bool_old_episode = False
        else:
            bool_old_episode = self.episodes['Name'] == episodes['Name']

        index_insert = list(set(index) - set(self.index))
        index_remove = list(set(self.index) - set(index))

        if bool_old_episode and not index_insert and not index_remove: # same episode, same index
            return
        elif not bool_old_episode: # new item / cell
            index_insert = index
            index_remove = []
            self.episodes = episodes
            self.episodes['Data'] = [[]] * len(self.episodes['Dirs'])
            self._loaded_array = []

        # update index
        self.index += index_insert
        for a in index_remove:
            self.index.remove(a)

        # Insert new episodes
        for i in index_insert:
            self.episodes['Data'][i] = NeuroData(dataFile=self.episodes['Dirs'][i], old=True, infoOnly=False, getTime=True)
            self._loaded_array.append(i)
            # call self.drawPlot
            self.drawEpisode(self.episodes['Data'][i], info=(self.episodes['Name'], self.episodes['Epi'][i]))

        # Remove episodes
        for j in index_remove:
            self.removeEpisode(info=(self.episodes['Name'], self.episodes['Epi'][j]))

    def drawEpisode(self, zData, info=None, pen=None):
        """Draw plot from 1 zData"""
        # Set up pen color
        if self.options['colorfy']:
            availableColors = list(colors)
            for c in self._usedColors:
                availableColors.remove(c)
            pen = availableColors[0]
            self._usedColors.append(pen)
        elif pen is None:
            pen = self.options['theme']['pen']

        # Loop through all the subplots
        for n, l in enumerate(self.options['layout']):
            # get viewbox
            p = self.graphicsView.getItem(row=l[2], col=l[3])
            if p is None:
                p = self.graphicsView.addPlot(row=l[2], col=l[3])
                # Make sure later viewboxes are linked in time domain
                if n>0:
                    p.setXLink(self.graphicsView.getItem(row=0, col=0))

            # put an identifier on the trace
            if isinstance(info, tuple):
                pname = info[0]+'.'+info[1]+'.'+l[0]+'.'+l[1]
            else:
                pname = None

            p.plot(x=zData.Time, y=getattr(zData, l[0])[l[1]], pen=pen, name=pname)


    def removeEpisode(self, info=None):
        if not info:
            return

        for l in self.options['layout']:
            # get viewbox
            p1 = self.graphicsView.getItem(row=l[2], col=l[3])
            pname = info[0]+'.'+info[1]+'.'+l[0]+'.'+l[1]

            remove_index = []
            for k, a in enumerate(p1.listDataItems()):
                if a.name() == pname: # matching
                    p1.removeItem(a)
                    remove_index.append(k)

        # recover the colors
        if remove_index and self.options['colorfy']:
            for r in remove_index:
                del self._usedColors[r]

    # ----------------------- Layout utilities --------------------------------
    def setLayout(self):
        return


    # ----------------------- Option utilities ----------------------------------
    def toggleTraceColors(self, checked):
        """Change traces from black to color coded"""
        # if already painted in color, paint in default pen again
        if not checked:
            self.options['colorfy'] = False
            self._usedColors = [] # reset used colors
        else:
            self.options['colorfy'] = True
        
        for l in self.options['layout']:
            # get viewbox
            p = self.graphicsView.getItem(row=l[2], col=l[3])
            for k, a in enumerate(p.listDataItems()):
                if not checked:
                    pen = self.options['theme']['pen']
                else:
                    pen = colors[k%len(colors)]
                    if pen not in self._usedColors:
                        self._usedColors.append(pen)
                pen = pg.mkPen(pen)
                a.setPen(pen)
        
    def setDisplayTheme(self, theme='whiteboard'):
        self.options['theme'] = {'blackboard':{'background':'k', 'pen':'w'}, \
                 'whiteboard':{'background':'w', 'pen':'k'}\
                }.get(theme)

        self.graphicsView.setBackground(self.options['theme']['background'])
class widget_pl_grid( QWidget ) :

	#-----------------------------------------------------------------------
	# DEFINE THE INITIALIZATION FUNCTION.
	#-----------------------------------------------------------------------

	def __init__( self, core, n,
	              n_plt_x=None, n_plt_y=None, n_plt=None ) :

		# Inherit all attributes of an instance of "QWidget".

		super( widget_pl_grid, self ).__init__( )

		# Initialize the counter of repaint events for this widget as
		# well as a maximum value for this counter.

		# Note.  For some reason, adjusting the individual plots to have
		#        uniform sizes is difficult to achieve before the widget
		#        is rendered.  Thus, once a paint event occurs, the
		#        "self.paintEvent( )" function picks it up and makes a
		#        call to "self.ajst_grd( )".  This counter and its
		#        maximum value are used ensure that "self.paintEvent( )"
		#        makes such a call only in response to the intial few
		#        painting (so as to prevent an infinite loop).

		# Note.  The first paint seems to be a "dummy" of some sort.
		#        Whatever the case, "self.n_paint_max = 1" seems to
		#        generally be insufficient.

		self.n_painted     = 0
		self.n_painted_max = 3

		# Disable user events

		self.setDisabled( True )

		self.core = core
		self.n = n
		self.t = []
		self.delta_t = []
		self.time_label = QLabel( ' ' )
		self.time_label.setAlignment( Qt.AlignCenter )
		self.time_label.setContentsMargins( 0,5,0,0 )
		font = QFont( )
		font.setBold(True)
		self.time_label.setFont( font )

		# Prepare to respond to signals received from the Janus core.

		self.connect( self.core, SIGNAL('janus_rset'),  self.resp_rset )
		self.connect( self.core, SIGNAL('janus_chng_pl_spc'),
		                                            self.resp_chng_pl_spc )
		self.connect( self.core, SIGNAL('janus_chng_mom_pl_sel'),
		                                     self.resp_chng_mom_pl_sel )
		self.connect( self.core, SIGNAL('janus_chng_mom_pl_res'),
		                                     self.resp_chng_mom_pl_res )
		self.connect( self.core, SIGNAL('janus_chng_nln_gss'),
		                                        self.resp_chng_nln_gss )
		self.connect( self.core, SIGNAL('janus_chng_nln_sel_all'),
		                                    self.resp_chng_nln_sel_all )
		self.connect( self.core, SIGNAL('janus_chng_nln_res'),
		                                    self.resp_chng_nln_res )
		self.connect( self.core, SIGNAL('janus_chng_dsp'),
		                                            self.resp_chng_dsp )

		#TODO add more signals

		# Assign (if not done so already) and store the shape of the
		# plot-grid array.

		self.n_plt_x = 5 if ( n_plt_x is None ) else n_plt_x
		self.n_plt_y = 5 if ( n_plt_y is None ) else n_plt_y

		if ( n_plt is None ) :
			self.n_plt = self.n_plt_x * self.n_plt_y

		# Initizalize the pens, brushes, and fonts used by this widget.

		self.pen_plt   = mkPen( color='k' )
		self.pen_hst   = mkPen( color='k' )
		self.pen_pnt_c = mkPen( color='k' )
		self.pen_pnt_y = mkPen( color='k' )
		self.pen_pnt_r = mkPen( color='k' )
		self.pen_crv_b = mkPen( color='b' )
		self.pen_crv_g = mkPen( color='g' )

		self.bsh_pnt_c = mkBrush( color='c' )
		self.bsh_pnt_y = mkBrush( color='y' )
		self.bsh_pnt_r = mkBrush( color='r' )

		self.fnt = self.core.app.font( )

		# Set the maximum number of velocity channels and the maximum
		# number of ion species.

		self.n_k   = 14
		self.n_ion = self.core.nln_n_pop

		# Initialize the widget and it's plot's.

		self.init_plt( )

		# Populate the plots with the histograms (and labels), the
		# selection points, and the fit curves.

		self.make_hst( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR INITIALIZING THE WIDGET AND ITS PLOTS.
	#-----------------------------------------------------------------------

	def init_plt( self ) :

		# Initialize the "GraphicsLayoutWidget" for this widget.  This
		# will allow a grid of "GraphicsItem" objects, which will
		# include the plots themselves, the axes, and the axis labels.

		# Note.  The "QGridLayout" object given to this widget as its
		#        layout is essentially a dummy.  I tried to just having
		#        this widget be an extention of "GraphicsLayoutWidget"
		#        (i.e., having it inheret that type), but I couldn't get
		#        it to display anything at all.

		self.setLayout( QGridLayout( ) )

		self.grd = GraphicsLayoutWidget( )
		self.grd.setBackground( 'w' )
		self.layout( ).addWidget( self.time_label )
		self.layout( ).addWidget( self.grd )

		self.layout().setContentsMargins( 0, 0, 0, 0 )

		# Initialize the text for the x- and y-axis labels.  Then,
		# create the labels themselves and add them to the grid.

		self.txt_axs_x = 'Projected Proton Inflow Velocity [km/s]'
		self.txt_axs_y = 'Phase-space Density' +\
		                                u'[cm\u00AF\u00B3/(km/s)\u00B3]'

		if ( self.core.app.res_lo ) :
			size =  '8pt'
		else :
			size = '10pt'

		self.lab_axs_x = LabelItem( self.txt_axs_x, angle=0  ,
		                            color='b', size=size       )
		self.lab_axs_y = LabelItem( self.txt_axs_y, angle=270, 
		                            color='b', size=size       )

		self.grd.addItem( self.lab_axs_x, self.n_plt_y + 1, 2,
		                                  1, self.n_plt_x      )
		self.grd.addItem( self.lab_axs_y, 0, 0,
		                                  self.n_plt_y, 1      )

		# Initialize the arrays that will contain the individual axes,
		# plots, and plot elements (i.e., the histograms, fit curves,
		# labels, and selection points).

		self.plt = tile( None, [ self.n_plt_y, self.n_plt_x ] )

		self.axs_x = tile( None, self.n_plt_x )
		self.axs_y = tile( None, self.n_plt_y )

		self.hst = tile( None, [ self.n_plt_y, self.n_plt_x ] )
		self.lbl = tile( None, [ self.n_plt_y, self.n_plt_x ] )

		self.crv     = tile( None, [ self.n_plt_y, self.n_plt_x ] )
		self.crv_ion = tile( None, [ self.n_plt_y, self.n_plt_x,
		                             self.n_ion                  ] )

		self.pnt = tile( None, [ self.n_plt_y, self.n_plt_x, 
		                         self.n_k                    ] )

		# Initialize the scale-type for each axis, then generate the
		# (default) axis-limits and adjusted axis-limits.

		self.log_x = False
		self.log_y = True

		self.make_lim( )

		# Create, store, and add to the grid the individual axes: first
		# the horizontal and then the vertical.

		for i in range( self.n_plt_x ) :

			self.axs_x[i] = AxisItem( 'bottom', maxTickLength=5 )
			self.axs_x[i].setLogMode( self.log_x )
			self.axs_x[i].setRange( self.x_lim[0], self.x_lim[1] )
			self.axs_x[i].setTickFont( self.fnt )

			if ( self.core.app.res_lo ) :
				self.axs_x[i].setHeight( 10 )
			else :
				self.axs_x[i].setHeight( 20 )

			self.grd.addItem( self.axs_x[i], self.n_plt_y, i + 2 )

		for j in range( self.n_plt_y ) :

			self.axs_y[j] = AxisItem( 'left', maxTickLength=5 )
			self.axs_y[j].setLogMode( self.log_y )
			self.axs_y[j].setRange( self.y_lim[0], self.y_lim[1] )
			self.axs_y[j].setTickFont( self.fnt )

			if ( self.core.app.res_lo ) :
				self.axs_y[j].setWidth( 32 )
			else :
				self.axs_y[j].setWidth( 40 )

			self.grd.addItem( self.axs_y[j], j, 1 )

		# Create, store, and add to the grid the individual plots.
		# Likewise, create, store, and add to each plot a label.

		for t in range( self.n_plt_y ) :

			for p in range( self.n_plt_x ) :

				# Compute the plot number of this plot.

				d = p + ( t * self.n_plt_x )

				# If creating this plot would exceed the
				# specified number of plots, don't create it.

				if ( d >= self.n_plt ) :
					continue

				# Create and store this plot, adjust its limits,
				# and add it to the grid.
				# Note: locations of plots are inverted along
				# theta

				self.plt[t,p] = event_ViewBox( self,
				                          border=self.pen_plt,
				                          enableMouse=False,
				                          enableMenu=False     )

				self.plt[t,p].setRange( xRange=self.x_lim,
				                        yRange=self.y_lim,
				                        padding=0.         )

				self.grd.addItem( self.plt[t,p], self.n_plt_y-t-1, p + 2 )

				# Create and store an (empty) label and add it
				# to this plot.

				self.lbl[t,p] = TextItem( anchor=(1,0) )

				self.lbl[t,p].setFont( self.fnt )

				self.plt[t,p].addItem( self.lbl[t,p] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR GENERATING AXIS-LIMITS (AND ADJUSTED LIMITS).
	#-----------------------------------------------------------------------

	def make_lim( self ) :

		# If no spectrum has been loaded, use the default limits;
		# otherwise, use the spectral data to compute axis limits.
		# Note: velocities are recorded in reverse order.

		if ( self.core.pl_spec_arr == [] ) :

			self.domain = [ 300. , 900. ]
			self.range = [ 1.e-10,  1.e-5 ]

		else :

			self.domain = [self.core.pl_spec_arr[self.n]['vel_strt'][0],
			               self.core.pl_spec_arr[self.n]['vel_stop'][-1]]

			arr_psd_flat = [self.core.pl_spec_arr[self.n]['psd_flat'][i] for i
			          in (where(array(self.core.pl_spec_arr[self.n]['psd_flat'])
			                                             != 0.)[0])]

			self.range = [ self.core.mom_psd_min, self.core.mom_psd_max  ]

			# Note: psd values are less than 1

			if ( self.log_y ) :
				self.range[0] = self.range[0] ** 1.05
				self.range[1] = self.range[1] ** 0.9
			else :
				self.range[1] += 0.1 * ( self.range[1] -
				                         self.range[0]   )

		# Compute the "adjusted limits" for each axis.

		if ( self.log_x ) :
			self.x_lim = [ log10( x ) for x in self.domain ]
		else :
			self.x_lim = self.domain

		if ( self.log_y ) :
			self.y_lim = [ log10( y ) for y in self.range ]
		else :
			self.y_lim = self.range

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CREATING THE PLOTS' HISTOGRAMS (AND LABELS).
	#-----------------------------------------------------------------------

	def make_hst( self ) :

		# Reset the timestamp label

		self.time_label.setText( ' ' )

		# If no spectrum has been loaded, abort.

		if ( self.core.pl_spec_arr == [] ) :

			return

		# If the index of this P-L grid is outside the bounds of the P-L
		# spectrum currently loaded, abort.

		if ( self.n >= len( self.core.pl_spec_arr ) ) :

			return		

		# Generate the timestamp label

		self.t = self.t + [self.core.pl_spec_arr[self.n]['time'][0]]

		self.t_0 = self.core.fc_spec['time']

		self.delta_t = self.delta_t + [( self.t[-1]-
		                                 self.t_0    ).total_seconds( )]


		self.time_label.setText( str(self.t[-1])[0:-7] + '        ' +
		                         u'\u0394t = {}'.format(
		                         round( self.delta_t[-1], 0) ) + 's' )

		# Use the spectral data to compute new axis-limits.

		self.make_lim( )

		for p in range( self.n_plt_x ) :
			 self.axs_x[p].setRange( self.x_lim[0], self.x_lim[1] )

		for t in range( self.n_plt_y ) :
			 self.axs_y[t].setRange( self.y_lim[0], self.y_lim[1] )

		# Histograms are broken down by phi horizontally and
		# theta vertically

		for t in range( self.core.pl_spec_arr[self.n]['n_the'] ):

			for p in range ( self.core.pl_spec_arr[self.n]['n_phi'] ):

				# If this plot does not exist, move onto
				# the next one.

				if ( self.plt[t,p] is None ) :
					continue

				#-----------------------------#
				#---DATA GENERATION SECTION---#
				#-----------------------------#

				# Generate a step function for the
				# look direction associated with this widget.

				self.stp = array( [step( self.core.pl_spec_arr[self.n]['vel_cen'],
				                        self.core.pl_spec_arr[self.n]['vel_del'],
				                        self.core.pl_spec_arr[self.n]['psd'][t][p])])

				# Calculate the points to be plotted from the
				# step function

				stp_pnt = array( [ array( datum.calc_pnt( 
				                     lev_min=self.range[0]/2.) )
				                   for datum in self.stp     ] )

				self.x_set = stp_pnt[:,0][0]
				self.y_set = stp_pnt[:,1][0]

				# If plotting log(y) and there are any psd
				# values of zero, replace those points with an
				# arbitrary minimum y value

				if ( self.log_y ) :
					y_min = self.range[0]/2.
					self.y_lim[0] = log10(y_min)
					self.y_set = [ max( y, y_min ) for y
					                         in self.y_set ]

				# If generating a log plot, take the log of the
				# points to be plotted

				self.x_pnts = log10( self.x_set ) if ( self.log_x ) else \
				                     self.x_set
				self.y_pnts = log10( self.y_set ) if ( self.log_y ) else \
				                     self.y_set

				#---------------------------------#
				#---GRAPHICS GENERATION SECTION---#
				#---------------------------------#

				# If a histogram already exists for this plot,
				# remove and delete it.

				if ( self.hst[t,p] is not None ) :
					self.plt[t,p].removeItem(self.hst[t,p])
					self.hst[t,p] = None

				# Clear this plot's label of text.

				self.lbl[t,p].setText( '' )

				# Adjust this plot's limits and then move it's
				# label in response.

				self.plt[t,p].setRange( xRange=self.x_lim,
				                        yRange=self.y_lim,
				                        padding=0.         )

				self.lbl[t,p].setPos( self.x_lim[1],
				                      self.y_lim[1]  )

				# Update this plot's label with appropriate text
				# indicating the pointing direction.


				elev = round( self.core.pl_spec_arr[self.n]['elev_cen'][t] )
				azim = round( self.core.pl_spec_arr[self.n]['azim_cen'][p] )

				txt = ( u'({0:+.0f}\N{DEGREE SIGN}, ' + 
				        u'{1:+.0f}\N{DEGREE SIGN})'     ).format(
				                                          elev, azim-180 )

				self.lbl[t,p].setText( txt, color=(0,0,0) )

				# Generate the histogram for the data from this
				# look direction and display it in the plot.

				self.hst[t,p] = PlotDataItem( self.x_pnts,
				                              self.y_pnts,
				                              pen=self.pen_hst )

				self.plt[t,p].addItem( self.hst[t,p] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CREATING THE PLOTS' SELECTION POINTS.
	#-----------------------------------------------------------------------

	def make_pnt( self ) :

		# If no spectrum has been loaded, abort.

		if ( self.core.pl_spec_arr == [] ) : return

		# If the index of this P-L grid is outside the bounds of the P-L
		# spectrum currently loaded, abort.

		if ( self.n >= len( self.core.pl_spec_arr ) ) : return

		# Add selection points to each plot.

		for d in range( min( self.core.pl_spec_arr[self.n]['n_dir'], self.n_plt ) ) :

			# Determine the location of this plot within the grid
			# layout.

			t = d // self.n_plt_x
			p = d %  self.n_plt_y

			# If this plot does not exist, move onto the next one.

			if ( self.plt[t,p] is None ) :
				continue

			# Add the selection points to this plot.

			for b in range( self.core.pl_spec_arr[self.n]['n_bin'] ) :

				sel_bin = False
				sel_dir = True
				sel_alt = None

				if( self.core.dsp == 'mom' ):

					sel_bin = self.core.pl_spec_arr[self.n].arr[t][p][b]['mom_sel']

				elif ( ( self.core.dsp == 'gsl' or self.core.dsp == 'nln' ) and 
				       ( self.core.nln_pl_sel is not None )  ) :

					sel_bin = self.core.nln_pl_sel[self.n][t][p][b]

#				elif ( ( self.core.dsp == 'nln'        ) and 
#				       ( self.core.pl_spec_arr[self.n].nln_res_sel
#					                   is not None )     ) :

#					sel_bin = \
#					       self.core.nln_pl_sel[t][p][b]

#					if ( self.core.pl_spec_arr[self.n].nln_sel is None ) :
#						sel_alt = None
#					else :
#						sel_alt = \
#						   self.core.pl_spec_arr[self.n].nln_sel[t][p][b]

				self.chng_pnt( t, p, b, sel_bin,
					       sel_alt=sel_alt   )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CHANGING THE VISIBILITY OF A DATUM'S POINTS.
	#-----------------------------------------------------------------------

	def chng_pnt( self, t, p, b, sel_bin, sel_alt=None ) :

		# If no spectrum has been loaded, abort.

		if ( self.core.pl_spec_arr == [] ) : return

		# If the index of this P-L grid is outside the bounds of the P-L
		# spectrum currently loaded, abort.

		if ( self.n >= len( self.core.pl_spec_arr ) ) : return

		# If this point already exists, remove it from its plot and
		# delete it.

		if ( self.pnt[t,p,b] is not None ) :
			self.plt[t,p].removeItem( self.pnt[t,p,b] )
			self.pnt[t,p,b] = None

		# If this point was not selected (based on both its primary and
		# secondary states), return (since there's nothing more to be
		# done).

		if ( not sel_bin or self.core.pl_spec_arr[self.n]['psd'][t][p][b] == 0) :
			return

		# Determine the "d" index corresponding to this look direction.

		d = p + ( t * self.n_plt_x )

		# Computed the adjusted point location in the "ViewBox".

		if ( self.log_x ) :
			ax = log10( self.core.pl_spec_arr[self.n]['vel_cen'][b] )
		else :
			ax = self.core.pl_spec_arr[self.n]['vel_cen'][b]
		if ( self.log_y ) :
			ay = log10( self.core.pl_spec_arr[self.n]['psd'][t][p][b] )
		else :
			ay = self.core.pl_spec_arr[self.n]['psd'][t][p][b]

		# Select the color for the point (i.e., the brush and pen used
		# to render it) based on whether or not this datum's look
		# direction has been selected and whether or not the primary and
		# secondary selection states match.

#		if ( sel_bin == sel_alt ) :
		pen   = self.pen_pnt_c
		brush = self.bsh_pnt_c
#		else :
#			pen   = self.pen_pnt_y
#			brush = self.bsh_pnt_y
#		else :
#			pen   = self.pen_pnt_r
#			brush = self.bsh_pnt_r

		# Select the symbol based on the values of the primary and
		# secondary selection states.

		# Note.  At this point in the code, at least one of these two
		#        states must be "True" since this -- when both states
		#        are "False", this function returns before it reaches
		#        this point.

		if ( sel_bin ) :
			symbol = 'o'
		else :
			symbol = 't'

		# Create, store, and add this selection point to the plot.

		if ( self.core.app.res_lo ) :
			size = 3
		else :
			size = 6

		self.pnt[t,p,b] = PlotDataItem( [ax], [ay],
		                                symbol=symbol,
		                                symbolSize=size,
		                                symbolPen=pen,
		                                symbolBrush=brush )

		self.plt[t,p].addItem( self.pnt[t,p,b] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR CREATING THE PLOTS' FIT CURVES.
	#-----------------------------------------------------------------------

	def make_crv( self ) :

		# If no "list" of "p" index-values has been provided by the
		# user, assume that the curves in all plots should be
		# (re-)rendered.

		if ( self.core.pl_spec_arr == [] ) :
			return

		# If the index of this P-L grid is outside the bounds of the P-L
		# spectrum currently loaded, abort.

		if ( self.n >= len( self.core.pl_spec_arr ) ) : return

		# Return the "nln_psd_gss_ion axes to their original order.

		if( self.core.nln_psd_gss_ion is not None ) :

			if( self.core.nln_psd_gss_ion != [ ] ) :

				nln_psd_gss_ion = [ [ [ [ [
				self.core.nln_psd_gss_ion[n][t][f][b][p]
				for b in range( self.core.pl_spec_arr[n]['n_bin'] ) ]
				for f in range( self.core.pl_spec_arr[n]['n_phi'] ) ]
				for t in range( self.core.pl_spec_arr[n]['n_the'] ) ]
				for n in range( len( self.core.pl_spec_arr      ) ) ]
				for p in range( self.core.nln_gss_n_pop           ) ]

		# Return the "nln_res_psd_ion axes to their original order.

		if( self.core.nln_res_psd_ion is not None ) :

			if( self.core.nln_res_psd_ion != [ ] ) :

				nln_res_psd_ion = [ [ [ [ [
				self.core.nln_res_psd_ion[n][t][f][b][p]
				for b in range( self.core.pl_spec_arr[n]['n_bin'] ) ]
				for f in range( self.core.pl_spec_arr[n]['n_phi'] ) ]
				for t in range( self.core.pl_spec_arr[n]['n_the'] ) ]
				for n in range( len( self.core.pl_spec_arr      ) ) ]
				for p in range( self.core.nln_gss_n_pop           ) ]

		# For each plot in the grid, generate and display a fit curve
		# based on the results of the analysis.

		vel_cen = self.core.pl_spec_arr[self.n]['vel_cen']

		for t in range( self.core.pl_spec_arr[self.n]['n_the'] ) :

			for p in range( self.core.pl_spec_arr[self.n]['n_phi'] ) :

				# If this plot does not exist, move onto the next grid
				# element.

				if ( self.plt[t,p] is None ) :
					continue

				# If any curves already exist for this plot, remove and
				# delete them.

				if ( self.crv[t,p] is not None ) :
					self.plt[t,p].removeItem( self.crv[t,p] )
					self.crv[t,p] = None

				for n in range( self.n_ion ) :
					if ( self.crv_ion[t,p,n] is not None ) :
						self.plt[t,p].removeItem(
						                   self.crv_ion[t,p,n] )
						self.crv_ion[t,p,n] = None

				# Create and add the curve of the indiviadual
				# contributions to the modeled psd to the plot.

				for n in range( ( 1 if self.core.dsp == 'mom' else self.core.nln_gss_n_pop ) ) :

					# Extract the points for this fit curve.

					x = array( vel_cen )

					if( self.core.dsp == 'mom' ) :

						y = array( self.core.pl_spec_arr[self.n]['psd_mom'][t][p] )

					elif( self.core.dsp == 'gsl' ) :

						y = array( nln_psd_gss_ion[n][self.n][t][p] )

					elif( self.core.dsp == 'nln' ) :

						y = array( nln_res_psd_ion[n][self.n][t][p] )

					# If any points are 0 or None, set them
					# to an arbitrary minimum value

					for tk in range(len(y)):
						if ( ( y[tk] == 0    ) or
						     ( y[tk] is None )    ) :
							y[tk] = 1e-20

					if ( self.log_x ) :
						ax = log10( x )
					else :
						ax = x

					if ( self.log_y ) :
						ay = array( [ log10( v )
						              for v in y ] )
					else :
						ay = y

					# Create, store, and add to the plot
					# this fit curve.

					self.crv_ion[t,p,n] = PlotDataItem(
					            ax, ay, pen=( self.pen_crv_b if self.core.dsp=='mom' else self.pen_crv_g ) )

					self.plt[t,p].addItem(
					                   self.crv_ion[t,p,n] )

				# If applicable, create and add the curve of the
				# total contributions to the modeled psd to the
				# plot

				if( self.core.dsp == 'gsl' ) :

					x = array( vel_cen )

					y = array( self.core.nln_psd_gss_tot[self.n][t][p] )

					# If any points are 0 or None, set them
					# to an arbitrary minimum value

					for tk in range(len(y)):
						if ( ( y[tk] == 0    ) or
						     ( y[tk] is None )    ) :
							y[tk] = 1e-20

					if ( self.log_x ) :
						ax = log10( x )
					else :
						ax = x

					if ( self.log_y ) :
						ay = array( [ log10( v )
						              for v in y ] )
					else :
						ay = y

					# Create, store, and add to the plot
					# this fit curve.

					self.crv[t,p] = PlotDataItem(
					            ax, ay, pen=( self.pen_crv_b ) )

					self.plt[t,p].addItem(
					                   self.crv[t,p] )

				# If applicable, create and add the curve of the
				# total contributions to the non-linear psd to
				# the plot

				if( ( self.core.dsp == 'nln' ) and
				    ( self.core.nln_res_psd_tot is not None ) ) :

					x = array( vel_cen )

					y = array( self.core.nln_res_psd_tot[self.n][t][p] )

					# If any points are 0 or None, set them
					# to an arbitrary minimum value

					for tk in range(len(y)):
						if ( ( y[tk] == 0    ) or
						     ( y[tk] is None )    ) :
							y[tk] = 1e-20

					if ( self.log_x ) :
						ax = log10( x )
					else :
						ax = x

					if ( self.log_y ) :
						ay = array( [ log10( v )
						              for v in y ] )
					else :
						ay = y

					# Create, store, and add to the plot
					# this fit curve.

					self.crv[t,p] = PlotDataItem(
					            ax, ay, pen=( self.pen_crv_b ) )

					self.plt[t,p].addItem(
					                   self.crv[t,p] )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESETTING THE PLOTS' HISTOGRAMS (AND LABELS).
	#-----------------------------------------------------------------------

	def rset_hst( self, rset_lbl=False ) :

		self.time_label.setText( '' )
		self.t = []
		self.delta_t = []

		# For each plot that exists in the grid, remove and delete it's
		# histogram.  Likewise, if requested, empty it's label (but
		# still leave the label itself intact).

		for t in range( self.n_plt_y ) :

			for p in range( self.n_plt_x ) :

				# If the plot does not exist, move onto the the
				# next one.

				if ( self.plt[t,p] is None ) :
					continue

				# If a histogram exists for this plot, remove
				# and delete it.

				if ( self.hst[t,p] is not None ) :
					self.plt[t,p].removeItem(
					                         self.hst[t,p] )
					self.hst[t,p] = None

				# If requested, reset this plot's label text to
				# the empty string.

				if ( rset_lbl ) :
					self.lbl[t,p].setText( '',
					                       color=(0,0,0) )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESETTING THE PLOTS' SELECTION POINTS.
	#-----------------------------------------------------------------------

	def rset_pnt( self ) :

		# For each plot that exists in the grid, hide and remove its
		# selection points.

		for t in range( self.n_plt_y ) :

			for p in range( self.n_plt_x ) :

				# If the plot does not exist, move onto the the
				# next grid element.

				if ( self.plt[t,p] is None ) :
					continue

				# Remove and then delete each of this plot's
				# selection points.

				for b in range( self.n_k ) :
					if ( self.pnt[t,p,b] is not None ) :
						self.plt[t,p].removeItem(
						               self.pnt[t,p,b] )
						self.pnt[t,p,b] = None

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESETTING THE PLOTS' FIT CURVES.
	#-----------------------------------------------------------------------

	def rset_crv( self ) :

		# For each plot that exists in the grid, remove and delete its
		# fit curves.

		for t in range( self.n_plt_y ) :

			for p in range( self.n_plt_x ) :

				# If the plot does not exist, move onto the the
				# next one.

				if ( self.plt[t,p] is None ) :
					continue

				# Remove and delete this plot's fit curve.

				if ( self.crv[t,p] is not None ) :
					self.plt[t,p].removeItem(
					                         self.crv[t,p] )
					self.crv[t,p] = None

				for n in range( self.n_ion ) :

					if ( self.crv_ion[t,p,n] is not None ) :
						self.plt[t,p].removeItem(
						           self.crv_ion[t,p,n] )
						self.crv_ion[t,p,n] = None

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "rset" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_rset( self ) :

		# Clear the plots of all their elements.

		self.rset_hst( )
		self.rset_pnt( )
		self.rset_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_spc" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_pl_spc( self ) :

		# Clear the plots of all their elements and regenerate them.

		self.rset_crv( )
		self.rset_pnt( )
		self.rset_hst( )

		self.make_hst( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_pl_res" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_mom_pl_sel( self ) :

		# If the results of the moments analysis are being displayed,
		# reset any existing fit curves and make new ones.

		self.make_pnt( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_pl_res" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_mom_pl_res( self ) :

		# If the results of the moments analysis are being displayed,
		# reset any existing fit curves and make new ones.

		self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_gss" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_nln_gss( self ) :

		# If the initial guess for the non-linear analysis is being
		# displayed, reset any existing fit curves and make new ones.

		if ( self.core.dsp == 'gsl' ) :

			self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_sel_all" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_nln_sel_all( self ) :

		# If the point selection for the non-linear analysis is being
		# displayed, reset any existing selection points and create new
		# ones.

		if ( ( self.core.dsp == 'gsl' ) or
		     ( self.core.dsp == 'nln' )    ) :

			self.make_pnt( )
#			self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_dsp" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_dsp( self ) :

		# Reset the selection points and fit curves.

		self.make_pnt( )
		self.make_crv( )

	#-----------------------------------------------------------------------
	# DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_dsp" SIGNAL.
	#-----------------------------------------------------------------------

	def resp_chng_nln_res( self ) :

		# Reset the fit curves.

		self.make_crv( )

	'''
示例#5
0
class CustomGraphicsLayoutWidget(GraphicsLayoutWidget):
    def __init__(self,
                 nName: tuple = ("Temperature", "Heater Power"),
                 nUnit: tuple = ("degC", "%P"),
                 parent=None):

        assert len(nName) == len(nUnit)
        pyqtgraph.setConfigOption('background', 'w')
        pyqtgraph.setConfigOption('foreground', 'k')

        super(CustomGraphicsLayoutWidget, self).__init__(parent)

        self.nName = nName
        self.nUnit = nUnit
        self.curves = []
        self.graphs = []
        self.legends = []
        self._samples = DEFAULT_SAMPLES
        self._plt = GraphicsLayoutWidget()

    def set_mode(self, mode):
        if mode == "Manual":
            self.is_manmode = True
        else:
            self.is_manmode = False
        self._clear_plot()
        self._configure_plot()

    def _clear_plot(self):

        self.clear()  #this is crucial fiuhh
        self.curves = []
        self.graphs = []

    def _configure_plot(self):
        n = len(self.nName)
        npos = np.linspace(1, n, n)
        if self.is_manmode:
            self.nLine = 1
            self.legend = MANUAL_LEGEND
        else:
            self.nLine = 2
            self.legend = PID_LEGEND

        for name, ypos, unit in zip(self.nName, npos, self.nUnit):
            self._plt.setBackground(background=None)
            self._plt.setAntialiasing(True)
            if name == self.nName[-1]:
                graph = self.addPlot(labels={
                    'right': name,
                    'bottom': "Waktu (detik)"
                })
            else:
                graph = self.addPlot(labels={'right': name})
            for i in range(self.nLine):
                curve = [graph.plot()]
                self.curves.extend(curve)
            graph.setLabel('right', name, unit)
            self.graphs.append(graph)
            self.nextRow()

    def get_curves(self):
        print("original curves: {}".format(self.curves))
        return self.curves

    def get_graphs(self):
        print("original graphs: {}".format(self.graphs))
        return self.graphs

    def get_legend(self):
        return self.legends
示例#6
0
class mainWindow(QMainWindow):
    # Metodo constructor de la clase
    def __init__(self):
        #Inicia el objeto QMainWindow
        QMainWindow.__init__(self)
        #carga la configuracion del archivo .ui en el objeto
        loadUi("mainWindowPPG.ui", self)
        # Loads everything about mainWindowPPG configuration
        self.setupUI()
        # Shared variables, initial values
        self.queue = Queue(N_SAMPLES)
        self.dataR = deque([], maxlen=N_SAMPLES)
        self.dataIR = deque([], maxlen=N_SAMPLES)
        self.TIME = deque([], maxlen=N_SAMPLES)
        self._plt = None
        self._timer_plot = None
        self.plot_colors = ['#0072bd', '#d95319']
        # configures
        self._configure_plot()
        self._configure_timers()
        self._configure_signals()

# Loads everything about mainWindowPPG configuration

    def setupUI(self):
        """
       Configures everything about the mainWindow
        """
        self.plt = GraphicsLayoutWidget(
            self.centralwidget)  # Bringing my plot wiindow as plt
        self.plt.setAutoFillBackground(False)
        self.plt.setStyleSheet("border: 0px;")
        self.plt.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.plt.setFrameShadow(QtWidgets.QFrame.Plain)
        self.plt.setLineWidth(0)
        self.Layout_graphs.addWidget(self.plt, 0, 0, 1,
                                     1)  # Set the plotting squared graph

    def _configure_plot(self):
        """
        Configures specific elements of the PyQtGraph plots.
        :return:
        """
        self.plt.setBackground(background=None)
        self.plt.setAntialiasing(True)
        self._plt = self.plt.addPlot(row=1, col=1)
        self._plt.setLabel('bottom', "Time", "s")
        pass

    def _configure_timers(self):
        """
        Configures specific elements of the QTimers.
        :return:
        """
        self._timer_plot = QtCore.QTimer(
            self)  # gives _timer_plot the attribute of QtCore.QTimer
        self._timer_plot.timeout.connect(
            self._update_plot)  # connects with _update_plot method
        pass

    def _update_plot(self):
        """
        Updates and redraws the graphics in the plot.
        This function us connected to the timeout signal of a QTimer.
        :return:
        """
        # Spo2 signal parameters
        f = 2
        amp1 = 0.5  # amplitud for Sine signal
        zeroDes1 = 0.5413  # Desplacement from zero for Sine signal
        amp2 = 0.5  # amplitud for Cosine signal
        zeroDes2 = 1.5413  # Desplacement from zero for Cosine signal
        # generate the time
        tsignal = time() - self.timestamp
        # Sine signal function
        sR = zeroDes1 + amp1 * 0.8 * np.sin(2 * np.pi * tsignal * 3 * f)
        # Cosine signal function
        sIR = zeroDes2 + amp2 * 0.8 * np.cos(2 * np.pi * tsignal * 3 * f)
        # put the data generate (time & signal) into queue
        self.queue.put([tsignal, sR, sIR])
        # get the data generate into queue
        data = self.queue.get(True, 1)
        # store data into variables
        self.TIME.append(data[0])
        self.dataR.append(data[1])
        self.dataIR.append(data[2])
        # Draw new data
        self._plt.clear()
        self._plt.plot(x=list(self.TIME)[-PLOT_UPDATE_POINTS:],
                       y=list(self.dataR)[-PLOT_UPDATE_POINTS:],
                       pen=self.plot_colors[1])
        self._plt.plot(x=list(self.TIME)[-PLOT_UPDATE_POINTS:],
                       y=list(self.dataIR)[-PLOT_UPDATE_POINTS:],
                       pen=self.plot_colors[0])

    def _configure_signals(self):
        """
        Configures the connections between signals and UI elements.
        :return:
        """
        self.startButton.clicked.connect(self.start)
        self.stopButton.clicked.connect(self.stop)

    def start(self):
        """
        Starts the acquisition of the selected serial port.
        This function is connected to the clicked signal of the Start button.
        :return:
        """
        self.timestamp = time()
        self._timer_plot.start(16)

    def stop(self):
        """
        Stops the acquisition of the selected serial port.
        This function is connected to the clicked signal of the Stop button.
        :return:
        """
        self._timer_plot.stop()  # stop the Qt timer
        self.reset_buffers()  # Go to reset the vector containing values

    def reset_buffers(self):
        self.dataR.clear()
        self.dataIR.clear()
        self.TIME.clear()
class Ui_MainWindow(object):

    def variables(self):
        self.D1_='D1'
        self.D2_='D2'
        self.D3_='D3'
        self.AVF_='AVF'
        self.AVR_='AVR'
        self.AVL_='AVL'
        self.GENRAL_='GENRAL'

    

    def setupUi(self, MainWindow):

        try:
            base_path= sys._MEIPASS
        except Exception:
            base_path=os.path.abspath(".")
        


        path1 = os.path.join(base_path, "imagen1.jpeg")
        path2 = os.path.join(base_path, "imagen2.jpeg")


        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1350, 747)
        #MainWindow.setStyleSheet("background-color: blue;")
        
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButtonAbrir = QtWidgets.QPushButton(self.centralwidget)
        self.pushButtonAbrir.setGeometry(QtCore.QRect(280, 10, 300, 32))
        self.pushButtonAbrir.setObjectName("pushButtonAbrir")
        #self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        #self.pushButton_2.setGeometry(QtCore.QRect(510, 90, 151, 41))
        #self.pushButton_2.setObjectName("pushButton_2")

        self.graphicsView = GraphicsLayoutWidget(self.centralwidget)
        self.graphicsView.setGeometry(QtCore.QRect(750, 230, 585, 370))
        self.graphicsView.setObjectName("graphicsView")
        
        #self.graphicsView.setBackground(background=None)

        self.label_7 = QtWidgets.QLabel(self.centralwidget)
        self.label_7.setGeometry(QtCore.QRect(1050, 1, 300, 100))
        self.label_7.setObjectName("label_7")
        pixmap = QPixmap(path1)
        self.label_7.setPixmap(pixmap)


        self.label_8 = QtWidgets.QLabel(self.centralwidget)
        self.label_8.setGeometry(QtCore.QRect(800, 1, 300, 100))
        self.label_8.setObjectName("label_8")
        pixmap = QPixmap(path2)
        self.label_8.setPixmap(pixmap)

        #Persona que creo el programa
        self.label_9 = QtWidgets.QLabel(self.centralwidget)
        self.label_9.setGeometry(QtCore.QRect(1000, 630, 2000, 70))
        self.label_9.setObjectName("label_9")

        #Nombre del proyecto
        self.label_10 = QtWidgets.QLabel(self.centralwidget)
        self.label_10.setGeometry(QtCore.QRect(1000, 595, 2000, 70))
        self.label_10.setObjectName("label_10")

        #Parametros de la persona
        self.label_nom = QtWidgets.QLabel(self.centralwidget)
        self.label_nom.setGeometry(QtCore.QRect(800, 20, 800, 200))
        self.label_nom.setObjectName("label_nom")

        self.label_edad = QtWidgets.QLabel(self.centralwidget)
        self.label_edad.setGeometry(QtCore.QRect(800, 60, 800, 200))
        self.label_edad.setObjectName("label_edad")

        self.label_sexo = QtWidgets.QLabel(self.centralwidget)
        self.label_sexo.setGeometry(QtCore.QRect(800, 100, 800, 200))
        self.label_sexo.setObjectName("label_sexo")

        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(20, 40, 675, 841))
        self.groupBox.setObjectName("groupBox")
        
        self.graphicD1 = GraphicsLayoutWidget(self.groupBox)
        self.graphicD1.setObjectName("graphicD1")
        self.graphicD1.setGeometry(QtCore.QRect(65, 30, 1000, 110))
        self.graphicD1.setBackground(background=None)

        self.graphicD2 = GraphicsLayoutWidget(self.groupBox)
        self.graphicD2.setObjectName("graphicD2")
        self.graphicD2.setGeometry(QtCore.QRect(65, 130, 1000, 110))
        self.graphicD2.setBackground(background=None)

        self.graphicD3 = GraphicsLayoutWidget(self.groupBox)
        self.graphicD3.setObjectName("graphicD3")
        self.graphicD3.setGeometry(QtCore.QRect(65, 230, 1000, 110))
        self.graphicD3.setBackground(background=None)

        self.graphicD3_2 = GraphicsLayoutWidget(self.groupBox)
        self.graphicD3_2.setObjectName("graphicD3_2")
        self.graphicD3_2.setGeometry(QtCore.QRect(65, 330, 1000, 110))
        self.graphicD3_2.setBackground(background=None)

        self.graphicD3_3 = GraphicsLayoutWidget(self.groupBox)
        self.graphicD3_3.setGeometry(QtCore.QRect(65, 430, 1000, 110))
        self.graphicD3_3.setObjectName("graphicD3_3")
        self.graphicD3_3.setBackground(background=None)

        self.graphicD3_4 = GraphicsLayoutWidget(self.groupBox)
        self.graphicD3_4.setObjectName("graphicD3_4")
        self.graphicD3_4.setGeometry(QtCore.QRect(65, 530, 1000, 110))
        self.graphicD3_4.setBackground(background=None)
       

        self.label = QtWidgets.QLabel(self.groupBox)
        self.label.setGeometry(QtCore.QRect(10, 65, 50, 24))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.groupBox)
        self.label_2.setGeometry(QtCore.QRect(10, 165, 50, 24))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.groupBox)
        self.label_3.setGeometry(QtCore.QRect(10, 265, 50, 24))
        self.label_3.setObjectName("label_3")

        self.label_4 = QtWidgets.QLabel(self.groupBox)
        self.label_4.setGeometry(QtCore.QRect(10, 365, 60, 24))
        self.label_4.setObjectName("label_4")
        self.label_5 = QtWidgets.QLabel(self.groupBox)
        self.label_5.setGeometry(QtCore.QRect(10, 465, 60, 24))
        self.label_5.setObjectName("label_5")
        self.label_6 = QtWidgets.QLabel(self.groupBox)
        self.label_6.setGeometry(QtCore.QRect(10, 565, 60, 24))
        self.label_6.setObjectName("label_6")
        
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 863, 22))
        self.menubar.setObjectName("menubar")
    
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        
        self.retranslateUi(MainWindow)
        self.pushButtonAbrir.clicked.connect(self.mybutton_clicked)
        #self.pushButton_2.clicked.connect(self.generatedReport)

        #Cajas de texto

        self.line_nom = QtWidgets.QLineEdit(self.centralwidget)
        self.line_nom.resize(200, 32)
        self.line_nom.move(875, 100)

        self.line_edad = QtWidgets.QLineEdit(self.centralwidget)
        self.line_edad.resize(200, 32)
        self.line_edad.move(875, 140)

        #self.line_sexo = QtWidgets.QLineEdit(self.centralwidget)
        #self.line_sexo.resize(200, 32)
        #self.line_sexo.move(875, 180)

        self.combo_sexo = QtWidgets.QComboBox(self.centralwidget)
        self.combo_sexo.resize(200, 32)
        self.combo_sexo.move(875, 180)
        self.combo_sexo.addItems(["None","Male","Female" ])
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        



    def mybutton_clicked(self):
        try:
            self.variables()
            #Nombre de encabezados del archivo CSV
            

            persona = {"Nombre":self.line_nom.text(),"Edad":self.line_edad.text(),"Genero":self.combo_sexo.currentText()}
            combo_textt =self.combo_sexo.currentText()
            #print(combo_textt)

            filename= QtWidgets.QFileDialog.getOpenFileName()
            df = pandas.read_csv(filename[0])

            x_max=df['x'].max()

            a=(df["x"])/4
            b= (df["x"]+x_max)/4
            c= (df["x"]+(2*x_max))/4
            d= (df["x"]+(3*x_max))/4
            r = pandas.concat([a,b,c,d])
            s= pandas.concat([df[self.D1_],df[self.D1_],df[self.D1_],df[self.D1_]])
            t= pandas.concat([df[self.D2_],df[self.D2_],df[self.D2_],df[self.D2_]])
            u= pandas.concat([df[self.D3_],df[self.D3_],df[self.D3_],df[self.D3_]])
            v= pandas.concat([df[self.AVF_],df[self.AVF_],df[self.AVF_],df[self.AVF_]])
            w= pandas.concat([df[self.AVR_],df[self.AVR_],df[self.AVR_],df[self.AVR_]])
            x= pandas.concat([df[self.AVL_],df[self.AVL_],df[self.AVL_],df[self.AVL_]])
            y= pandas.concat([df[self.GENRAL_],df[self.GENRAL_],df[self.GENRAL_],df[self.GENRAL_]])
            df = pandas.DataFrame({"x":r, "D1":s,"D2":t,"D3":u,"AVF":v,"AVR":w,"AVL":x,"GENRAL":y})




            self.d1_INTERVAL_1=df.query('x >= 3.03 & x <= 3.08')#st
            self.d1_INTERVAL_2=df.query('x >= 1.7 & x <= 1.9')#t
            self.d1_INTERVAL_3=df.query('x >= 4.2 & x <= 4.3')#p
            self.d1_INTERVAL_1_MAX= self.d1_INTERVAL_1[self.D1_].max()
            self.d1_INTERVAL_2_MAX= self.d1_INTERVAL_2[self.D1_].max()
            self.d1_INTERVAL_3_MAX= self.d1_INTERVAL_3[self.D1_].max()

            self.d2_INTERVAL_1=df.query('x >= 15.4 & x <= 15.44')#ST
            self.d2_INTERVAL_2=df.query('x >= 16.2 & x <= 16.4')#T
            self.d2_INTERVAL_3=df.query('x >= 16.6 & x <= 16.7')#P
            self.d2_INTERVAL_1_MAX= self.d2_INTERVAL_1[self.D2_].max()
            self.d2_INTERVAL_2_MAX= self.d2_INTERVAL_2[self.D2_].max()
            self.d2_INTERVAL_3_MAX= self.d2_INTERVAL_3[self.D2_].max()

            self.d3_INTERVAL_1=df.query('x >= 67.01 & x <= 67.05')#st
            self.d3_INTERVAL_2=df.query('x >= 49.85 & x <= 50')#t
            self.d3_INTERVAL_3=df.query('x >= 50.35 & x <= 50.45')#p
            self.d3_INTERVAL_1_MAX= self.d3_INTERVAL_1[self.D3_].max()
            self.d3_INTERVAL_2_MAX= self.d3_INTERVAL_2[self.D3_].max()
            self.d3_INTERVAL_3_MAX= self.d3_INTERVAL_3[self.D3_].max()

            self.avf_INTERVAL_1=df.query('x >= 111.635    & x <= 111.7')#st
            self.avf_INTERVAL_2=df.query('x >= 113.82 & x <= 114')#t
            self.avf_INTERVAL_3=df.query('x >= 153.4 & x <= 153.545')#p
            self.avf_INTERVAL_1_MAX= self.avf_INTERVAL_1[self.AVF_].max()
            self.avf_INTERVAL_2_MAX= self.avf_INTERVAL_2[self.AVF_].max()
            self.avf_INTERVAL_3_MAX= self.avf_INTERVAL_3[self.AVF_].max()

            self.avr_INTERVAL_1=df.query('x >= 99.27 & x <= 99.29')#st
            self.avr_INTERVAL_2=df.query('x >= 102.06& x <= 102.26')#t
            self.avr_INTERVAL_3=df.query('x >= 105.95 & x <= 106.09')#p
            self.avr_INTERVAL_1_MAX= self.avr_INTERVAL_1[self.AVR_].min()
            self.avr_INTERVAL_2_MAX= self.avr_INTERVAL_2[self.AVR_].min()
            self.avr_INTERVAL_3_MAX= self.avr_INTERVAL_3[self.AVR_].min()

            self.avl_INTERVAL_1=df.query('x >= 95.93 & x <= 96.12')#st
            self.avl_INTERVAL_2=df.query('x >= 104.75 & x <= 104.8')#t
            self.avl_INTERVAL_3=df.query('x >= 130.67 & x <= 130.81')#p
            self.avl_INTERVAL_1_MAX= self.avl_INTERVAL_1[self.AVL_].max()
            self.avl_INTERVAL_2_MAX= self.avl_INTERVAL_2[self.AVL_].max()
            self.avl_INTERVAL_3_MAX= self.avl_INTERVAL_3[self.AVL_].max()


            #VALORES ST Y T

            values_ST_T ={  self.D1_:
                                {
                                    "d1_INTERVAL_1_MAX":self.d1_INTERVAL_1_MAX,
                                    "d1_INTERVAL_2_MAX":self.d1_INTERVAL_2_MAX,
                                    "d1_INTERVAL_3_MAX":self.d1_INTERVAL_3_MAX
                                },
                            self.D2_:
                                {
                                    "d2_INTERVAL_1_MAX":self.d2_INTERVAL_1_MAX,
                                    "d2_INTERVAL_2_MAX":self.d2_INTERVAL_2_MAX,
                                    "d2_INTERVAL_3_MAX":self.d2_INTERVAL_3_MAX
                                },
                            self.D3_:
                                {
                                    "d3_INTERVAL_1_MAX":self.d3_INTERVAL_1_MAX,
                                    "d3_INTERVAL_2_MAX":self.d3_INTERVAL_2_MAX,
                                    "d3_INTERVAL_3_MAX":self.d3_INTERVAL_3_MAX

                                },
                            self.AVF_:
                                {
                                    "avf_INTERVAL_1_MAX":self.avf_INTERVAL_1_MAX,
                                    "avf_INTERVAL_2_MAX":self.avf_INTERVAL_2_MAX,
                                    "avf_INTERVAL_3_MAX":self.avf_INTERVAL_3_MAX

                                },
                            self.AVR_:
                                {
                                    "avr_INTERVAL_1_MAX":self.avr_INTERVAL_1_MAX,
                                    "avr_INTERVAL_2_MAX":self.avr_INTERVAL_2_MAX,
                                    "avr_INTERVAL_3_MAX":self.avr_INTERVAL_3_MAX
                                },
                            self.AVL_:
                                {
                                    "avl_INTERVAL_1_MAX":self.avl_INTERVAL_1_MAX,
                                    "avl_INTERVAL_2_MAX":self.avl_INTERVAL_2_MAX,
                                    "avl_INTERVAL_3_MAX":self.avl_INTERVAL_3_MAX,
                                }
                        }

            #Intervalo general
            limit=16
            GENER_INTERVAL=df.query('x >= 236 & x <= 243')
            print(GENER_INTERVAL)
            contPuls=0
            bandera = True


            for index, row in GENER_INTERVAL.iterrows():
                if int(row[self.GENRAL_]) >= limit and bandera==True:
                    contPuls = contPuls + 1
                    bandera = False
                elif  int(row[self.GENRAL_])<limit and bandera == False:
                    contPuls = contPuls + 1
                    bandera = True


            #Graficar valores
            
            

            self.graphicD1.plot(x=df['x'], y=df[self.D1_], pen='#2196F3')

            self.graphicD2.plot(x=(df['x']), y=df[self.D2_], pen='#2196F3')

            self.graphicD3.plot(x=(df['x']), y=df[self.D3_], pen='#2196F3')

            self.graphicD3_2.plot(x=(df['x']), y=df[self.AVF_], pen='#2196F3')

            self.graphicD3_3.plot(x=(df['x']), y=df[self.AVR_], pen='#2196F3')

            self.graphicD3_4.plot(x=(df['x']), y=df[self.AVL_], pen='#2196F3')

            self.graphicsView.plot(x=(df['x']), y=df[self.GENRAL_], pen='#2196F3')

            self.graphicsView.setLabel("bottom", "Time / s")

            self.generatedReport(df,persona,values_ST_T,contPuls/2)
        except NameError:
            print("error: "+NameError)


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "RECAHOLT"))
        MainWindow.setWindowIcon(QtGui.QIcon('ico.png'))
        self.pushButtonAbrir.setText(_translate("MainWindow", "Open file and report generator"))
        #self.pushButton_2.setText(_translate("MainWindow", "Generar Reporte"))
        self.label_9.setText(_translate("MainWindow", "by Jonathan Recalde"))
        self.label_9.setFont(QtGui.QFont('Times', 20))
        self.label_10.setText(_translate("MainWindow", "RECAHOLT"))
        self.label_10.setFont(QtGui.QFont('Times', 20))
        self.groupBox.setTitle(_translate("MainWindow", "Graphics"))
        self.groupBox.setFont(QtGui.QFont('Times', 20))
        self.label.setText(_translate("MainWindow", "D1"))
        self.label_2.setText(_translate("MainWindow", "D2"))
        self.label_3.setText(_translate("MainWindow", "D3"))
        self.label_4.setText(_translate("MainWindow", "aVF"))
        self.label_5.setText(_translate("MainWindow", "aVR"))
        self.label_6.setText(_translate("MainWindow", "aVL"))
        self.label_nom.setText(_translate("MainWindow", "Name:"))
        self.label_edad.setText(_translate("MainWindow", "Age:"))
        self.label_sexo.setText(_translate("MainWindow", "Gender:"))

        self.graphicD1 = self.graphicD1.addPlot(row=1, col=1)
        self.graphicD2 = self.graphicD2.addPlot(row=1, col=1)
        self.graphicD3 = self.graphicD3.addPlot(row=1, col=1)
        self.graphicD3_2 = self.graphicD3_2.addPlot(row=1, col=1)
        self.graphicD3_3 = self.graphicD3_3.addPlot(row=1, col=1)
        self.graphicD3_4 = self.graphicD3_4.addPlot(row=1, col=1)
        self.graphicsView = self.graphicsView.addPlot(row=1, col=1)



    def generatedReport(self,df,persona,values_ST_T,contPuls):
        #Valores D1
        D1_max= df[self.D1_].max()
        Time_D1=df.query("D1 == '{0}'".format(D1_max))
        int_timeD1= float(Time_D1["x"].values[0])

        ST_D1= values_ST_T[self.D1_]['d1_INTERVAL_1_MAX']
        Time_ST_D1=self.d1_INTERVAL_1.query("D1 == '{0}'".format(ST_D1))
        int_time_ST_D1= float(Time_ST_D1["x"].values[0])

        T_D1= values_ST_T[self.D1_]['d1_INTERVAL_2_MAX']
        Time_T_D1=self.d1_INTERVAL_2.query("D1 == '{0}'".format(T_D1))
        int_time_T_D1= float(Time_T_D1["x"].values[0])

        P_D1= values_ST_T[self.D1_]['d1_INTERVAL_3_MAX']
        Time_P_D1=self.d1_INTERVAL_3.query("D1 == '{0}'".format(P_D1))
        int_time_P_D1= float(Time_P_D1["x"].values[0])
        
        #Valores D2

        D2_max= df[self.D2_].max()
        Time_D2=df.query("D2 == '{0}'".format(D2_max))
        int_timeD2= float(Time_D2["x"].values[0])

        ST_D2= values_ST_T[self.D2_]['d2_INTERVAL_1_MAX']
        Time_ST_D2=self.d2_INTERVAL_1.query("D2 == '{0}'".format(ST_D2))
        int_time_ST_D2= float(Time_ST_D2["x"].values[0])
        
        T_D2= values_ST_T[self.D2_]['d2_INTERVAL_2_MAX']        
        Time_T_D2=self.d2_INTERVAL_2.query("D2 == '{0}'".format(T_D2))
        int_time_T_D2= float(Time_T_D2["x"].values[0])

        P_D2= values_ST_T[self.D2_]['d2_INTERVAL_3_MAX']        
        Time_P_D2=self.d2_INTERVAL_3.query("D2 == '{0}'".format(P_D2))
        int_time_P_D2= float(Time_P_D2["x"].values[0])

        #Valores D3

        D3_max= df[self.D3_].max()
        Time_D3=df.query("D3 == '{0}'".format(D3_max))
        int_timeD3= float(Time_D3["x"].values[0])

        ST_D3= values_ST_T[self.D3_]['d3_INTERVAL_1_MAX']
        Time_ST_D3=self.d3_INTERVAL_1.query("D3 == '{0}'".format(ST_D3))
        int_time_ST_D3= float(Time_ST_D3["x"].values[0])
        
        T_D3= values_ST_T[self.D3_]['d3_INTERVAL_2_MAX']        
        Time_T_D3=self.d3_INTERVAL_2.query("D3 == '{0}'".format(T_D3))
        int_time_T_D3= float(Time_T_D3["x"].values[0])

        P_D3= values_ST_T[self.D3_]['d3_INTERVAL_3_MAX']        
        Time_P_D3=self.d3_INTERVAL_3.query("D3 == '{0}'".format(P_D3))
        int_time_P_D3= float(Time_P_D3["x"].values[0])

        #Valores AVF

        AVF_max= df[self.AVF_].max()
        Time_AVF=df.query("AVF == '{0}'".format(AVF_max))
        int_timeAVF= float(Time_AVF["x"].values[0])

        ST_AVF= values_ST_T[self.AVF_]['avf_INTERVAL_1_MAX']
        Time_ST_AVF=self.avf_INTERVAL_1.query("AVF == '{0}'".format(ST_AVF))
        int_time_ST_AVF= float(Time_ST_AVF["x"].values[0])
        
        T_AVF= values_ST_T[self.AVF_]['avf_INTERVAL_2_MAX']        
        Time_T_AVF=self.avf_INTERVAL_2.query("AVF == '{0}'".format(T_AVF))
        int_time_T_AVF= float(Time_T_AVF["x"].values[0])

        P_AVF= values_ST_T[self.AVF_]['avf_INTERVAL_3_MAX']        
        Time_P_AVF=self.avf_INTERVAL_3.query("AVF == '{0}'".format(P_AVF))
        int_time_P_AVF= float(Time_P_AVF["x"].values[0])

        #Valores AVR

        AVR_max= df[self.AVR_].min()
        Time_AVR=df.query("AVR == '{0}'".format(AVR_max))
        int_timeAVR= float(Time_AVR["x"].values[0])

        ST_AVR= values_ST_T[self.AVR_]['avr_INTERVAL_1_MAX']
        Time_ST_AVR=self.avr_INTERVAL_1.query("AVR == '{0}'".format(ST_AVR))
        int_time_ST_AVR= float(Time_ST_AVR["x"].values[0])
        

        T_AVR= values_ST_T[self.AVR_]['avr_INTERVAL_2_MAX']      
        Time_T_AVR=self.avr_INTERVAL_2.query("AVR == '{0}'".format(T_AVR))
        int_time_T_AVR= float(Time_T_AVR["x"].values[0])

        P_AVR= values_ST_T[self.AVR_]['avr_INTERVAL_3_MAX']      
        Time_P_AVR=self.avr_INTERVAL_3.query("AVR == '{0}'".format(P_AVR))
        int_time_P_AVR= float(Time_P_AVR["x"].values[0])

        #Valores AVL

        AVL_max= df[self.AVL_].max()
        Time_AVL=df.query("AVL == '{0}'".format(AVL_max))
        int_timeAVL= float(Time_AVL["x"].values[0])

        ST_AVL= values_ST_T[self.AVL_]['avl_INTERVAL_1_MAX']
        Time_ST_AVL=self.avl_INTERVAL_1.query("AVL == '{0}'".format(ST_AVL))
        int_time_ST_AVL= float(Time_ST_AVL["x"].values[0])
        
        T_AVL= values_ST_T[self.AVL_]['avl_INTERVAL_2_MAX']        
        Time_T_AVL=self.avl_INTERVAL_2.query("AVL == '{0}'".format(T_AVL))
        int_time_T_AVL= float(Time_T_AVL["x"].values[0])

        P_AVL= values_ST_T[self.AVL_]['avl_INTERVAL_3_MAX']        
        Time_P_AVL=self.avl_INTERVAL_3.query("AVL == '{0}'".format(P_AVL))
        int_time_P_AVL= float(Time_P_AVL["x"].values[0])
        
        # ###################################
        # Content
        try:
            base_path= sys._MEIPASS
        except Exception:
            base_path=os.path.abspath(".")

        path5 = os.path.join(base_path, 'Report.pdf')

        fileName = path5

        documentTitle = 'ECG REPORT'
        title = 'ECG REPORT'
        subTitle = 'Name:'+persona["Nombre"] +" Age:"+persona["Edad"] +" Gender:"+persona["Genero"]

        textLines = [
        'D1 / R:'+str(float(D1_max))+'     ST: '+str(float(ST_D1))+'     T: '+str(float(T_D1))+'     P: '+str(float(P_D1)),
        'Time: '+str(float(int_timeD1)) +'  Time: '+str(float(int_time_ST_D1))+'  Time: '+str(float(int_time_T_D1))+'  Time: '+str(float(int_time_P_D1)),
        'D2 / R:'+str(float(D2_max))+'     ST: '+str(float(ST_D2))+'     T: '+str(float(T_D2)) +'     P: '+str(float(P_D2)),
        'Time: '+str(float(int_timeD2)) +'  Time: '+str(float(int_time_ST_D2))+'  Time: '+str(float(int_time_T_D2))+'  Time: '+str(float(int_time_P_D2)),
        'D3 / R:'+str(float(D3_max))+'     ST: '+str(float(ST_D3))+'     T: '+str(float(T_D3))+'     P: '+str(float(P_D3)),
        'Time: '+str(float(int_timeD3)) +'  Time: '+str(float(int_time_ST_D3))+'  Time: '+str(float(int_time_T_D3))+'  Time: '+str(float(int_time_P_D3)),
        'aVF / R:'+str(float(AVF_max)) +'     ST: '+str(float(ST_AVF))+'     T: '+str(float(T_AVF))+'     P: '+str(float(P_AVF)),
        'Time: '+str(float(int_timeAVF)) +'  Time: '+str(float(int_time_ST_AVF))+'  Time: '+str(float(int_time_T_AVF))+'  Time: '+str(float(int_time_P_AVF)),
        'aVR / R:'+str(float(AVR_max)) +'     ST: '+str(float(ST_AVR))+'     T: '+str(float(T_AVR))+'     P: '+str(float(P_AVR)),
        'Time: '+str(float(int_timeAVR)) +'  Time: '+str(float(int_time_ST_AVR))+'  Time: '+str(float(int_time_T_AVR))+'  Time: '+str(float(int_time_P_AVR)),
        'aVL / R:'+str(float(AVL_max)) +'     ST: '+str(float(T_AVL))+'     T: '+str(float(ST_AVL))+'     P: '+str(float(P_AVL)),
        'Time: '+str(float(int_timeAVL)) +'  Time: '+str(float(int_time_ST_AVL))+'  Time: '+str(float(int_time_T_AVL))+'  Time: '+str(float(int_time_P_AVL)),
        ]
        # ###################################
        # 0) Create document 
        from reportlab.pdfgen import canvas 

        pdf = canvas.Canvas(fileName)
        pdf.setTitle(documentTitle)

        #self.drawMyRuler#(pdf)
        # ###################################
        # 1) Title :: Set fonts 
        # # Print available fonts
        # for font in pdf.getAvailableFonts():
        #     print(font)

        # Register a new font
        from reportlab.pdfbase.ttfonts import TTFont
        from reportlab.pdfbase import pdfmetrics

        try:
            base_path= sys._MEIPASS
        except Exception:
            base_path=os.path.abspath(".")
        


        path4 = os.path.join(base_path, 'SakBunderan.ttf')
        print(path4)


        pdfmetrics.registerFont(
            TTFont('abc', path4)
        )
        pdf.setFont('abc', 36)
        pdf.drawCentredString(300, 770, title)

        # ###################################
        # 2) Sub Title 
        # RGB - Red Green and Blue
        pdf.setFillColorRGB(0, 0, 255)
        pdf.setFont("Courier-Bold", 24)
        pdf.drawCentredString(290,720, subTitle)

        # ###################################
        # 3) Draw a line
        pdf.line(30, 710, 550, 710)

        # ###################################
        # 4) Text object :: for large amounts of text
        from reportlab.lib import colors

        text = pdf.beginText(40, 680)
        text.setFont("Courier", 13)
        text.setFillColor(colors.red)
        val=True
        for line in textLines:
            text.textLine(line)
            if val:
                text.setFillColor(colors.black)
                val=False
            else :
                text.setFillColor(colors.red)
                val=True
                text.textLine("")

        #Valor maximo de X
        value_max_X=float(df["x"].max())/3600
        text.textLine("")
        text.textLine("")
        text.textLine("")
        text.textLine("")
        text.setFillColor(colors.blue)
        truncate = "%.6f" % value_max_X
        text.textLine('Connetion time: '+str(truncate) +" h")
        text.textLine("")
        text.textLine('Heart rate: '+str(round(contPuls)*10) +" bpm")
    

        pdf.drawText(text)
        pdf.save()