示例#1
0
 def populate_spectrogram_widget(self, widget: GraphicsLayoutWidget,
                                 game_name: str, player_name: PlayerName,
                                 electrode_name: str):
     # https://stackoverflow.com/questions/51312923/plotting-the-spectrum-of-a-wavfile-in-pyqtgraph-using-scipy-signal-spectrogram
     f, t, Sxx = self._acquire_spectrogram_signal(game_name, player_name,
                                                  electrode_name)
     plot = widget.addPlot()
     plot.setTitle('Frequency over time for electrode %s' %
                   ELECTRODES[electrode_name])
     img = ImageItem()
     plot.addItem(img)
     hist = HistogramLUTItem()
     hist.setImageItem(img)
     widget.addItem(hist)
     hist.setLevels(np.min(Sxx), np.max(Sxx))
     hist.gradient.restoreState({
         'mode':
         'rgb',
         'ticks': [(0.5, (0, 182, 188, 255)), (1.0, (246, 111, 0, 255)),
                   (0.0, (75, 0, 113, 255))]
     })
     img.setImage(Sxx)
     img.scale(t[-1] / np.size(Sxx, axis=1), f[-1] / np.size(Sxx, axis=0))
     plot.setLimits(xMin=0, xMax=t[-1], yMin=0, yMax=f[-1])
     plot.setLabel('bottom', "Time", units='s')
     plot.setLabel('left', "Frequency", units='Hz')
示例#2
0
def get_spectrogram(wav: WavFile, graphics_layout: pyqtgraph.GraphicsLayoutWidget):
    f, t, Sxx = signal.spectrogram(wav.data, wav.rate)

    # Interpret image data as row-major instead of col-major
    pyqtgraph.setConfigOptions(imageAxisOrder='row-major')
    pyqtgraph.mkQApp()
    graphics_layout.clear()
    plot_widget = graphics_layout.addPlot()
    # A plot area (ViewBox + axes) for displaying the image

    # Item for displaying image data
    img = pyqtgraph.ImageItem()
    plot_widget.addItem(img)
    # Add a histogram with which to control the gradient of the image
    hist = pyqtgraph.HistogramLUTItem()
    # Link the histogram to the image
    hist.setImageItem(img)
    # If you don't add the histogram to the window, it stays invisible, but I find it useful.
    graphics_layout.addItem(hist)
    # Show the window
    graphics_layout.show()
    # Fit the min and max levels of the histogram to the data available
    #print("min: "+ str(np.min(Sxx)) + "max:" + str(np.max(Sxx)))
    hist.setLevels(0, 40000)
    # This gradient is roughly comparable to the gradient used by Matplotlib
    # You can adjust it and then save it using hist.gradient.saveState()
    hist.gradient.restoreState(
        {'mode': 'rgb',
         'ticks': [(0.5, (0, 182, 188, 255)),
                   (1.0, (246, 111, 0, 255)),
                   (0.0, (75, 0, 113, 255))]})
    # Sxx contains the amplitude for each pixel
    img.setImage(Sxx)
    # Scale the X and Y Axis to time and frequency (standard is pixels)
    img.scale(t[-1] / np.size(Sxx, axis=1),
              f[-1] / np.size(Sxx, axis=0))
    # Limit panning/zooming to the spectrogram
    plot_widget.setLimits(xMin=0, xMax=t[-1], yMin=0, yMax=f[-1])
    # Add labels to the axis
    plot_widget.setLabel('bottom', "Time", units='s')
    # If you include the units, Pyqtgraph automatically scales the axis and adjusts the SI prefix (in this case kHz)
    plot_widget.setLabel('left', "Frequency", units='Hz')
示例#3
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( )
示例#4
0
class Graphexample():
    def __init__(self):
        self.graph = GraphicsLayoutWidget()
        self.graph.setObjectName("stock UI")
        self.label = pg.LabelItem(justify='right')
        self.graph.addItem(self.label)
        self.p1 = self.graph.addPlot(row=1, col=0)
        self.p2 = self.graph.addPlot(row=2, col=0)
        self.p1.showGrid(x=True, y=True, alpha=0.5)
        self.region = pg.LinearRegionItem()
        self.region.setZValue(10)
        # Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this
        # item when doing auto-range calculations.
        self.p2.addItem(self.region, ignoreBounds=True)

        #pg.dbg()
        self.p1.setAutoVisible(y=True)

        #create numpy arrays
        #make the numbers large to show that the xrange shows data from 10000 to all the way 0
        self.data1 = 10000 + 15000 * pg.gaussianFilter(
            np.random.random(size=10000),
            10) + 3000 * np.random.random(size=10000)
        self.data2 = 15000 + 15000 * pg.gaussianFilter(
            np.random.random(size=10000),
            10) + 3000 * np.random.random(size=10000)

        self.p1.plot(self.data1, pen="r")
        self.p1.plot(self.data2, pen="g")

        self.p2.plot(self.data1, pen="w")
        self.region.sigRegionChanged.connect(self.update)
        self.p1.sigRangeChanged.connect(self.updateRegion)

        self.region.setRegion([1000, 2000])

        #cross hair
        self.vLine = pg.InfiniteLine(angle=90, movable=False)
        self.hLine = pg.InfiniteLine(angle=0, movable=False)
        self.p1.addItem(self.vLine, ignoreBounds=True)
        self.p1.addItem(self.hLine, ignoreBounds=True)

        self.vb = self.p1.vb
        self.proxy = pg.SignalProxy(self.p1.scene().sigMouseMoved,
                                    rateLimit=60,
                                    slot=self.mouseMoved)

    def update(self):
        self.region.setZValue(10)
        minX, maxX = self.region.getRegion()
        self.p1.setXRange(minX, maxX, padding=0)

    def updateRegion(self, window, viewRange):
        rgn = viewRange[0]
        self.region.setRegion(rgn)

    def mouseMoved(self, evt):
        pos = evt[
            0]  ## using signal proxy turns original arguments into a tuple
        if self.p1.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            index = int(mousePoint.x())
            if index > 0 and index < len(self.data1):
                self.label.setText(
                    "<span style='font-size: 12pt'>x=%0.1f,   <span style='color: red'>y1=%0.1f</span>,   <span style='color: green'>y2=%0.1f</span>"
                    % (mousePoint.x(), self.data1[index], self.data2[index]))
            self.vLine.setPos(mousePoint.x())
            self.hLine.setPos(mousePoint.y())

    def ret_GraphicsLayoutWidget(self):
        return self.graph
示例#5
0
        self.ui_callback(self.current_state)


if __name__ == "__main__":

    app = QtGui.QApplication(sys.argv)
    main_window = QtGui.QMainWindow()

    sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
    video_view = VideoView()
    test_img = cv2.imread("Etaluma.png")
    video_view.setImage(test_img)
    video_view.stateUpdate(State.full_view)

    graphicsLayoutWidget = GraphicsLayoutWidget()
    main_window.setCentralWidget(graphicsLayoutWidget)
    graphicsLayoutWidget.addItem(video_view, 0, 0)
    graphicsLayoutWidget.setSizePolicy(sizePolicy)
    main_window.show()

    c = console.ConsoleWidget(namespace={
        's': video_view,
        'g': graphicsLayoutWidget,
        'n': main_window,
        'pg': pg
    })
    c.show()
    video_view.show()
    app.exec_()
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( )

	'''
示例#7
0
class StockGraph():
    def __init__(self, numofplot=2, name=None, stockInfo=None):
        self.gridContainer = None
        self.dir = None
        self.construct_gridlayout()
        if numofplot < 0:
            print("numofplot must be greater or equal than 0")
            return -1

        if name != None and len(name) > numofplot:
            print("Pls Checking numofplot")
            return -1
        #X-axis data
        self.dataX = None
        self.dataY = None
        self.name = name
        self.stockInfo = stockInfo
        self.graph = GraphicsLayoutWidget()
        self.graph.setObjectName("stock UI")
        self.label = pg.LabelItem(justify='right')
        self.graph.addItem(self.label)
        self.date_axis = TimeAxisItem(orientation='bottom')
        self.date_axis1 = TimeAxisItem(orientation='bottom')

        self.p1 = self.graph.addPlot(row=1,
                                     col=0,
                                     axisItems={'bottom': self.date_axis1})
        #p1 zoom in/out, move viewbox can auto scaling Y, Important!
        self.p1.vb.sigXRangeChanged.connect(self.setYRange)

        self.p2 = self.graph.addPlot(row=2,
                                     col=0,
                                     axisItems={'bottom': self.date_axis})
        #p2 zoom in/out, move viewbox can auto scaling Y. Important!
        self.p2.vb.sigXRangeChanged.connect(self.setYRange)

        # self.p1.showGrid(x=True, y=True, alpha=0.5)
        self.region = pg.LinearRegionItem()
        self.region.setZValue(10)
        # Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this
        # item when doing auto-range calculations.
        self.p2.addItem(self.region, ignoreBounds=True)

        self.p1.setAutoVisible(y=True)

        #cross hair
        self.vLine = pg.InfiniteLine(angle=90, movable=False)
        self.hLine = pg.InfiniteLine(angle=0, movable=False)
        self.p1.addItem(self.vLine, ignoreBounds=True)
        self.p1.addItem(self.hLine, ignoreBounds=True)

        self.vb = self.p1.vb
        self.proxy = pg.SignalProxy(self.p1.scene().sigMouseMoved,
                                    rateLimit=60,
                                    slot=self.mouseMoved)

        #Set PlotDataItem
        self.numofplot = numofplot
        self.name = name
        self.colorStyle = ['r', 'g', 'b', 'y', 'w', 'r']
        self.PlotDataItemList = self.setPlot()
        self.p2_plot = self.p2.plot(name='overview')

        #set gridContainer layout
        self.gridContainer.layout.addWidget(self.graph, 0, 0, 10, 1)
        self.gridContainer.setLayout(self.gridContainer.layout)

        self.calName = ['10avg', '30avg', '90avg']
        self.CalPlotDataItemList = self.setCalPlot()

        #consttuct graph control Panel
        self.construct_controlPanel()

    def construct_gridlayout(self):
        self.gridContainer = QtWidgets.QWidget()
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                           QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHeightForWidth(
            self.gridContainer.sizePolicy().hasHeightForWidth())
        self.gridContainer.setSizePolicy(sizePolicy)
        self.gridContainer.setFocusPolicy(QtCore.Qt.NoFocus)
        self.gridContainer.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        self.gridContainer.setObjectName("Graphgrid")
        self.gridContainer.layout = QtWidgets.QGridLayout()
        self.gridContainer.setStyleSheet("background-color:black;")

    def construct_controlPanel(self):
        self.maxRadioButton = QtWidgets.QCheckBox("Max")
        self.maxRadioButton.setObjectName("maxRadioButton")
        self.gridContainer.layout.addWidget(self.maxRadioButton, 0, 1, 1, 1)
        self.maxRadioButton.click()
        self.maxRadioButton.setStyleSheet("color: rgb(0, 255, 0);")
        self.maxRadioButton.toggled.connect(
            lambda: self.toggleFunc(self.maxRadioButton, 'high'))

        self.minRadioButton = QtWidgets.QCheckBox("Min")
        self.minRadioButton.setObjectName("minRadioButton")
        self.gridContainer.layout.addWidget(self.minRadioButton, 1, 1, 1, 1)
        self.minRadioButton.click()
        self.minRadioButton.setStyleSheet("color: rgb(255, 255, 255);")
        self.minRadioButton.toggled.connect(
            lambda: self.toggleFunc(self.minRadioButton, 'low'))

        self.closeRadioButton = QtWidgets.QCheckBox("Close")
        self.closeRadioButton.setObjectName("closeRadioButton")
        self.gridContainer.layout.addWidget(self.closeRadioButton, 2, 1, 1, 1)
        self.closeRadioButton.click()
        self.closeRadioButton.setStyleSheet("color: rgb(255,0,0);")
        self.closeRadioButton.toggled.connect(
            lambda: self.toggleFunc(self.closeRadioButton, 'close'))

        self.avg10RadioButton = QtWidgets.QCheckBox("10 AVG")
        self.avg10RadioButton.setObjectName("avg10RadioButton")
        self.gridContainer.layout.addWidget(self.avg10RadioButton, 3, 1, 1, 1)
        self.avg10RadioButton.click()
        self.avg10RadioButton.setStyleSheet("color: rgb(255,255,0);")
        self.avg10RadioButton.toggled.connect(
            lambda: self.toggleFunc(self.avg10RadioButton, '10avg'))

        self.GetButton = QtWidgets.QPushButton("Advance")
        self.GetButton.setObjectName("Advance")
        self.GetButton.clicked.connect(self.Analysis)
        self.GetButton.setStyleSheet("color: rgb(255, 255, 255);")
        self.gridContainer.layout.addWidget(self.GetButton, 4, 1, 1, 1)

    def update_p1_tick(self, minX, maxX, interval=60):
        if self.dataX != None:

            #0 - minX
            lowNum = int(minX / interval)
            #maxX - length
            HighNum = int((len(self.dataX) - 1 - maxX) / interval)

            plotPoint = [(minX - interval * i)
                         for i in range(1, lowNum + 1)] + [minX]
            if (maxX - minX) > interval:
                plotPoint.append(int((maxX + minX) / 2))
            plotPoint = plotPoint + [maxX] + [(maxX + interval * i)
                                              for i in range(1, HighNum + 1)]

            p1_tick = ['' for i in range(0, len(self.dataX))]
            p1_tick = dict(enumerate(p1_tick))
            for index in plotPoint:
                p1_tick[index] = self.dataX[index]

            self.date_axis1.setTicks([list(p1_tick.items())[::1]])

    def update(self):
        self.region.setZValue(10)
        minX, maxX = self.region.getRegion()
        self.p1.setXRange(minX, maxX, padding=0)
        if (maxX < len(self.dataX) - 1):
            self.update_p1_tick(int(minX) + 1, int(maxX))

    def updateRegion(self, window, viewRange):
        rgn = viewRange[0]
        self.region.setRegion(rgn)

    def mouseMoved(self, evt):
        pos = evt[
            0]  ## using signal proxy turns original arguments into a tuple

        if self.p1.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            index = int(mousePoint.x())

            if index > 0 and index < len(self.dataX):
                idx = int(mousePoint.x())
                self.label.setText(
                    "<span style='font-size: 12pt'>x=%s,   <span style='color: red'>收盤價=%0.1f</span>,   <span style='color: green'>最高價=%0.1f</span>  <span style='color: white'>最低價=%0.1f</span>"
                    % (self.dataX[idx], self.dataY['close'][idx],
                       self.dataY['high'][idx], self.dataY['low'][idx]))
            self.vLine.setPos(mousePoint.x())
            self.hLine.setPos(mousePoint.y())

    def setYRange(self, plotitem):
        plotitem.enableAutoRange(axis='y')
        plotitem.setAutoVisible(y=True)

    def setPlot(self):
        PlotDataItemList = []
        for i in range(0, self.numofplot):
            PlotDataItemList.append(
                self.p1.plot(pen=self.colorStyle[i], name=self.name[i]))
        return PlotDataItemList

    def setCalPlot(self):
        CalPlotDataItemList = []
        for i in range(0, 3):
            CalPlotDataItemList.append(
                self.p1.plot(pen=self.colorStyle[i + 3], name=self.calName[i]))
        return CalPlotDataItemList

    def setData(self, dataX, dataYDict):
        #create numpy arrays
        #make the numbers large to show that the xrange shows data from 10000 to all the way 0
        self.dataX = dataX
        self.dataY = dataYDict
        ticks = dict(enumerate(dataX))
        '''set X-value of P2 and P1'''
        self.date_axis.setTicks(
            [list(ticks.items())[::160],
             list(ticks.items())[::1]])
        self.date_axis1.setTicks(
            [list(ticks.items())[::160],
             list(ticks.items())[::1]])
        '''set Y-value and Plot'''
        for dataY, PlotDataItem in zip(dataYDict.values(),
                                       self.PlotDataItemList):
            PlotDataItem.setData(y=dataY)

        #do not show label
        #self.p1.getAxis('bottom').showLabel(False)

        # self.date_axis.linkToView(self.p1.vb)
        '''set overview data'''
        self.p2_plot.setData(x=list(ticks.keys()),
                             y=dataYDict[self.name[0]],
                             pen="w")
        #set data view range
        self.p2.vb.setLimits(xMin=0, xMax=len(dataYDict[self.name[0]]))
        self.region.sigRegionChanged.connect(self.update)
        # print (self.p2.vb.viewRange())

        # print (self.p1.vb)
        # self.p1.sigRangeChanged.connect(self.updateRegion)

        self.region.setRegion([0, len(dataYDict[self.name[0]])])

        #calculte Data
        avg10 = self.moving_average(dataYDict[self.name[0]], 10)
        self.CalPlotDataItemList[0].setData(y=avg10)

        #make Max and Min are invisiable by default
        self.minRadioButton.setChecked(False)
        self.maxRadioButton.setChecked(False)

    def toggleFunc(self, rdb, name):
        plotItem = None
        for plot in self.PlotDataItemList:
            if plot.name() == name:
                plotItem = plot
        for plot in self.CalPlotDataItemList:
            if plot.name() == name:
                plotItem = plot
        if rdb.isChecked():
            self.p1.addItem(plotItem)
        else:
            self.p1.removeItem(plotItem)

    def setDir(self, dir):
        self.dir = dir

    def Analysis(self):
        d = Dialog(self.dataY, self.dataX, self.dir, self.stockInfo)
        d.exec()

    def ret_GraphicsLayoutWidget(self):
        return self.gridContainer

    @staticmethod
    def removeEvent(self):
        return

    def moving_average(self, data, days):
        result = []
        NanList = [np.nan for i in range(0, days - 1)]
        data = data[:]
        for _ in range(len(data) - days + 1):
            result.append(round(sum(data[-days:]) / days, 2))
            data.pop()
        result = result[::-1]
        return NanList + result
示例#8
0
class Viewer:
    """
    abstraction layer on viewer that dispatches visualisation to specific components
    and implements widgets for DataSet functionality
    """
    def __init__(self, dataset):
        self.dataset = dataset

        self.napari_viewer = None
        self.plots = None
        self.blik_widget = None

    def show(self, napari_viewer=None, **kwargs):
        self.ensure_ready(napari_viewer=napari_viewer)
        for db in self.dataset:
            db.init_depictor(**kwargs)
        if self.dataset.volumes:
            self.show_volume(list(self.dataset.volumes.keys())[0])
        if self.dataset.plots:
            self.plots.show()

    @property
    def shown(self):
        if self.napari_viewer and self.volume_selector:
            return self.dataset.volumes[self.volume_selector.currentText()]
        return None

    def ensure_ready(self, napari_viewer=None):
        if napari_viewer is not None:
            self._init_viewer(napari_viewer)
            self._init_plots()
            self._init_blik_widget()
            self._hook_keybindings()
        # check if viewer exists and is still open
        try:
            self.napari_viewer.window.qt_viewer.actions()
        except (AttributeError, RuntimeError):
            self._init_viewer()
            self._init_plots()
            self._init_blik_widget()
            self._hook_keybindings()

    def _init_viewer(self, napari_viewer=None):
        if napari_viewer is not None:
            self.napari_viewer = napari_viewer
        else:
            self.napari_viewer = napari.Viewer(title='napari - Blik')
        self.napari_viewer.scale_bar.unit = '0.1nm'
        self.napari_viewer.scale_bar.visible = True
        # TODO: workaround until layer issues are fixed (napari #2110)
        self.napari_viewer.window.qt_viewer.destroyed.connect(self.dataset.purge_gui)

    def _init_plots(self):
        self.plots = GraphicsLayoutWidget()
        self._plots_napari_widget = self.napari_viewer.window.add_dock_widget(self.plots,
                                                                              name='Blik - Plots',
                                                                              area='bottom')
        # use napari hide and show methods
        self.plots.show = self._plots_napari_widget.show
        self.plots.hide = self._plots_napari_widget.hide
        self.plots.hide()

    def _init_blik_widget(self):
        self.blik_widget = QWidget()
        layout = QVBoxLayout()
        self.blik_widget.setLayout(layout)

        self.volume_selector = QComboBox(self.blik_widget)
        self.volume_selector.addItems(self.dataset.volumes.keys())
        self.volume_selector.currentTextChanged.connect(self.show_volume)
        layout.addWidget(self.volume_selector)

        self.plots_toggler = QPushButton('Show / Hide Plots')
        self.plots_toggler.clicked.connect(self.toggle_plots)
        layout.addWidget(self.plots_toggler)

        self._blik_napari_widget = self.napari_viewer.window.add_dock_widget(self.blik_widget,
                                                                           name='Blik',
                                                                           area='left')
        # use napari hide and show methods
        self.blik_widget.show = self._blik_napari_widget.show
        self.blik_widget.hide = self._blik_napari_widget.hide

    def _hook_keybindings(self):
        self.napari_viewer.bind_key('PageUp', self.previous_volume)
        self.napari_viewer.bind_key('PageDown', self.next_volume)

    def update_blik_widget(self):
        if self.blik_widget is not None:
            current_text = self.volume_selector.currentText()
            with block_signals(self.volume_selector):
                self.volume_selector.clear()
                self.volume_selector.addItems(self.dataset.volumes.keys())
                self.volume_selector.setCurrentText(current_text)
        self.show()

    def clear_shown(self):
        for layer in self.napari_viewer.layers.copy():
            if layer in self.dataset.napari_layers:
                self.napari_viewer.layers.remove(layer)
        self.plots.clear()

    def show_volume(self, volume):
        if volume is None:
            return
        self.volume_selector.setCurrentText(volume)
        datablocks = self.dataset.omni + self.dataset.volumes[volume]

        layers = []
        plots = []
        for db in datablocks:
            for dep in db.depictors:
                if hasattr(dep, 'layers'):
                    if not dep.layers:
                        dep.depict()
                    layers.extend(dep.layers)
                elif hasattr(dep, 'plot'):
                    if not dep.plot.curves:
                        dep.depict()
                    plots.append(dep.plot)
        layers = sorted(layers, key=lambda l: isinstance(l, napari.layers.Image), reverse=True)

        self.clear_shown()
        self.napari_viewer.layers.extend(layers)
        for plt in plots:
            self.plots.addItem(plt)

    def previous_volume(self, viewer=None):
        idx = self.volume_selector.currentIndex()
        previous_idx = (idx - 1) % self.volume_selector.count()
        self.volume_selector.setCurrentIndex(previous_idx)

    def next_volume(self, viewer=None):
        idx = self.volume_selector.currentIndex()
        next_idx = (idx + 1) % self.volume_selector.count()
        self.volume_selector.setCurrentIndex(next_idx)

    def toggle_plots(self):
        if self.plots.isVisible():
            self.plots.hide()
        else:
            self.plots.show()
示例#9
0
class Dialog(QtGui.QDialog):
    def __init__(self,
                 dataY=None,
                 dataX=None,
                 dir=None,
                 stockInfo=None,
                 parent=None):
        super(Dialog, self).__init__(parent)
        self.resize(800, 800)
        self.gridContainer = None
        self.gridContainer = QtWidgets.QWidget(self)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,
                                           QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHeightForWidth(
            self.gridContainer.sizePolicy().hasHeightForWidth())
        self.gridContainer.setSizePolicy(sizePolicy)
        self.gridContainer.setFocusPolicy(QtCore.Qt.NoFocus)
        self.gridContainer.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        self.gridContainer.setObjectName("Graphgrid")
        self.gridContainer.layout = QtWidgets.QGridLayout()
        self.dir = dir

        self.stockInfo = stockInfo

        self.dataX = dataX
        self.dataY = dataY
        self.rasingRange = []
        self.failingRange = []

        # setup Plot
        self.graph = None
        self.PlotDataItemList = None
        self.PlotLocalMaximaData = None
        self.PlotLocalMinimaData = None
        self.p1 = None
        self.colorStyle = ['r', 'g', 'y', 'b', 'w', 'o']
        self.setupGraph()
        self.gridContainer.layout.addWidget(self.graph, 0, 0, 10, 10)

        self.TableDAT = Concat_Table_With_IDX(self.dir, self.stockInfo.code)
        print(self.dir, self.stockInfo.code)
        self.initUI()
        self.proxy = pg.SignalProxy(self.p1.scene().sigMouseMoved,
                                    rateLimit=60,
                                    slot=self.mouseMoved)

    def initUI(self):
        #check box
        self.AVGRadioButton = QtWidgets.QCheckBox("AVG")
        self.AVGRadioButton.setObjectName("avgRadioButton")
        self.gridContainer.layout.addWidget(self.AVGRadioButton, 0, 11, 1, 1)
        self.AVGRadioButton.setStyleSheet("color: rgb(0, 255, 0);")
        self.AVGRadioButton.toggled.connect(
            lambda: self.toggleFunc(self.AVGRadioButton, 'avg'))
        self.AVGRadioButton.click()

        self.LPFRadioButton = QtWidgets.QCheckBox("LPF")
        self.LPFRadioButton.setObjectName("avgRadioButton")
        self.gridContainer.layout.addWidget(self.LPFRadioButton, 1, 11, 1, 1)
        self.LPFRadioButton.setStyleSheet("color: rgb(255,0,0);")
        self.LPFRadioButton.toggled.connect(
            lambda: self.toggleFunc(self.LPFRadioButton, 'lpf'))
        self.LPFRadioButton.click()

        #set Data
        self.PlotDataItemList = self.setPlot()
        self.setData(self.dataX, self.dataY)

        #set avg slide
        self.avgSld = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
        self.avgSld.setRange(5, 120)
        self.avgSld.setFocusPolicy(QtCore.Qt.NoFocus)
        # it seems not work
        #self.avgSld.setPageStep(5)
        # self.avgSld.setTickInterval(5)
        # self.avgSld.setSingleStep(5)
        self.avgSld.valueChanged.connect(self.updateAvg)
        self.gridContainer.layout.addWidget(self.avgSld, 11, 1, 1, 2)
        self.avg = functionAnalysis.moving_average(self.dataY['close'],
                                                   self.avgSld.value())

        self.AvgEdit = QtWidgets.QLabel('5日線')
        self.AvgEdit.setObjectName("avg")
        self.gridContainer.layout.addWidget(self.AvgEdit, 11, 0, 1, 1)

        self.OrderLabel = QtWidgets.QLabel('Order')
        self.OrderLabel.setObjectName("orderLabel")
        self.gridContainer.layout.addWidget(self.OrderLabel, 12, 0, 1, 1)

        self.OrderEdit = QtWidgets.QLineEdit("2")
        self.OrderEdit.setObjectName("orderEdit")
        self.gridContainer.layout.addWidget(self.OrderEdit, 12, 1, 1, 1)

        self.CutoffEdit = QtWidgets.QLabel("Cutoff : 2")
        self.CutoffEdit.setObjectName("Cutoff")
        self.gridContainer.layout.addWidget(self.CutoffEdit, 12, 3, 1, 1)

        self.cutoffSld = QtWidgets.QSlider(QtCore.Qt.Horizontal, self)
        self.cutoffSld.setRange(2, 60)

        self.cutoffSld.setFocusPolicy(QtCore.Qt.NoFocus)
        self.smoothData = functionAnalysis.butterworth_filter(
            self.dataY['close'], self.cutoffSld.value(),
            len(self.dataY['close']) / 2, 2)
        self.cutoffSld.valueChanged.connect(self.updateLPF)
        self.cutoffSld.setValue(5)

        self.gridContainer.layout.addWidget(self.cutoffSld, 12, 4, 1, 10)

        self.PlotDataItemList[1].setData(y=self.avg)
        self.PlotDataItemList[2].setData(y=self.smoothData)

        self.gridContainer.setLayout(self.gridContainer.layout)

        #make AVG is invisiable by default
        self.AVGRadioButton.setChecked(False)

        self.tableView = QtWidgets.QTableView()

        self.TableDAT = self.TableDAT.round(2)
        #Temporary, we delete 1st level colums, for showing columns in TableView
        self.TableDAT.columns = self.TableDAT.columns.droplevel(0)
        self.model = PandaModel.DataFrameModel(self.TableDAT)
        self.tableView.setModel(self.model)

        #Resize cell size to
        self.tableView.resizeColumnsToContents()
        self.gridContainer.layout.addWidget(self.tableView, 13, 0, 1, 10)

    def setupGraph(self):
        self.date_axis = TimeAxisItem(orientation='bottom')
        self.graph = GraphicsLayoutWidget()
        self.graph.setObjectName("Graph UI")
        self.date_axis = TimeAxisItem(orientation='bottom')
        self.label = pg.LabelItem(justify='right')
        self.graph.addItem(self.label)

        self.p1 = self.graph.addPlot(row=1,
                                     col=0,
                                     axisItems={'bottom': self.date_axis})
        #p1 zoom in/out, move viewbox can auto scaling Y, Important!
        self.p1.vb.sigXRangeChanged.connect(self.setYRange)

        self.PlotDataItemList = self.setPlot()
        self.PlotLocalMaximaData = pg.ScatterPlotItem(pen='r',
                                                      brush='b',
                                                      symbol='d',
                                                      pxMode=True,
                                                      size=10)
        self.PlotLocalMinimaData = pg.ScatterPlotItem(pen='g',
                                                      brush='b',
                                                      symbol='t',
                                                      pxMode=True,
                                                      size=10)
        # self.p1.addItem(self.PlotLocalMaximaData)
        # self.p1.addItem(self.PlotLocalMinimaData)

    # def showEvent(self, event):
    # 	geom = self.frameGeometry()
    # 	geom.moveCenter(QtGui.QCursor.pos())
    # 	self.setGeometry(geom)
    # 	super(Dialog, self).showEvent(event)

    def setPlot(self):
        PlotDataItemList = []
        self.name = ['close', 'avg', 'lpf']
        for i in range(0, 3):
            PlotDataItemList.append(
                self.p1.plot(pen=self.colorStyle[i], name=self.name[i]))
        return PlotDataItemList

    def setYRange(self, plotitem):
        plotitem.enableAutoRange(axis='y')
        plotitem.setAutoVisible(y=True)

    def setData(self, dataX, dataY):
        ticks = dict(enumerate(dataX))
        '''set X-value'''
        self.date_axis.setTicks(
            [list(ticks.items())[::120],
             list(ticks.items())[::1]])
        self.PlotDataItemList[0].setData(y=dataY['close'])

    def updateAvg(self, value):
        self.AvgEdit.setText(str(value) + '日線')
        self.avg = functionAnalysis.moving_average(self.dataY['close'],
                                                   self.avgSld.value())
        self.PlotDataItemList[1].setData(y=self.avg)

    def updateLPF(self, value):
        self.CutoffEdit.setText("Cutoff : " + str(value))
        self.smoothData = functionAnalysis.butterworth_filter(
            self.dataY['close'], self.cutoffSld.value(),
            len(self.dataY['close']) / 2, int(self.OrderEdit.text()))
        self.PlotDataItemList[2].setData(y=self.smoothData)
        maxidx, minidx = functionAnalysis.getlocalMaxMin(
            self.smoothData, True, True)

        #Split Range
        sortRange = []
        lastRoundIdx = 0
        for idxMax, idxMin in zip(maxidx, minidx):
            if idxMax > idxMin:
                sortRange.append([lastRoundIdx, idxMin])
                sortRange.append([idxMin, idxMax])
                lastRoundIdx = idxMax
            else:
                sortRange.append([lastRoundIdx, idxMax])
                sortRange.append([idxMax, idxMin])
                lastRoundIdx = idxMin
        sortRange.append([
            maxidx[-1], -1
        ]) if maxidx[-1] > minidx[-1] else sortRange.append([minidx[-1], -1])

        self.PlotLocalMaximaData.setData(
            x=maxidx, y=[self.dataY['close'][i] for i in maxidx])
        self.PlotLocalMinimaData.setData(
            x=minidx, y=[self.dataY['close'][i] for i in minidx])

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.hide()
            event.accept()
        else:
            super(Dialog, self).keyPressEvent(event)

    def toggleFunc(self, rdb, name):
        plotItem = None
        for plot in self.PlotDataItemList:
            if plot.name() == name:
                plotItem = plot
        if rdb.isChecked():
            self.p1.addItem(plotItem)
        else:
            self.p1.removeItem(plotItem)

    def mouseMoved(self, evt):
        pos = evt[
            0]  ## using signal proxy turns original arguments into a tuple

        if self.p1.sceneBoundingRect().contains(pos):
            mousePoint = self.p1.vb.mapSceneToView(pos)
            index = int(mousePoint.x())

            if index > 0 and index < len(self.dataX):
                idx = int(mousePoint.x())
                self.label.setText(
                    "<span style='font-size: 12pt'>x=%s,   <span style='color: red'>收盤價=%0.1f</span>"
                    % (self.dataX[idx], self.dataY['close'][idx]))