def create_sliders(self, width, height): """Creates the sliders, label for the slider, text with value of slider and the percentage sign.""" font = QtGui.QFont() x_pos = [int(width * x) for x in [0.05, 0.3, 0.55]] y_pos = [int(height * y) for y in [0.24, 0.33, 0.80]] wid = [int(width * x) for x in [0.15, 0.05, 0.04]] hei = [int(height * y) for y in [0.09, 0.44, 0.09]] i = 0 for mode in self.mode: font.setPixelSize(int(height * 0.07)) exec(f"self.{mode}_power_title = QtWidgets.QLabel(self)") exec(f"self.{mode}_power_title.setFont(font)") exec( f"self.{mode}_power_title.setAlignment(QtCore.Qt.AlignCenter)") exec( f"self.{mode}_power_title.setText('{self.mode_nl[self.mode.index(mode)]}')" ) exec( f"self.{mode}_power_title.setGeometry(QtCore.QRect({x_pos[i]}, {y_pos[0]}," f"{wid[0]}, {hei[0]}))") font.setPixelSize(int(height * 0.03)) exec(f"self.{mode}_power_value = QtWidgets.QLCDNumber(self)") exec( f"self.{mode}_power_value.setGeometry({x_pos[i]}, {y_pos[2]}, {wid[0]}, {hei[2]})" ) exec(f"self.{mode}_power_value.setFont(font)") exec(f"self.{mode}_power_value.setDigitCount(3)") exec(f"self.{mode}_power_value.display(0)") exec(f"self.{mode}_power_slider = QtWidgets.QSlider(self)") exec(f"self.{mode}_power_slider.setMaximum(100)") exec( f"self.{mode}_power_slider.setOrientation(QtCore.Qt.Vertical)") exec( f"self.{mode}_power_slider.setGeometry({x_pos[i]}, {y_pos[1]}," f"{wid[0]}, {hei[1]})") exec( f"self.{mode}_power_slider.valueChanged.connect(self.{mode}_power_value.display)" ) exec( f"self.{mode}_power_slider.sliderReleased.connect(self.update_data_manager)" ) font.setPixelSize(int(height * 0.07)) exec(f"self.{mode}_power_symb = QtWidgets.QLabel(self)") exec( f"self.{mode}_power_symb.setGeometry({x_pos[i] + int(width * 0.125)}, {y_pos[2]}," f"{wid[2]}, {hei[2]})") exec(f"self.{mode}_power_symb.setText('%')") exec(f"self.{mode}_power_symb.setFont(font)") i += 1 font.setPixelSize(int(height * 0.07)) self.opslag_title = QtWidgets.QLabel(self) self.opslag_title.setFont(font) self.opslag_title.setAlignment(QtCore.Qt.AlignCenter) self.opslag_title.setText('Opslaan') fac_scale = 0.2 self.opslag_title.setGeometry( QtCore.QRect(int(width * 0.8 - hei[0] * fac_scale / 2), y_pos[0], wid[0] * (1 + fac_scale), hei[0])) self.opslag_title.setStyleSheet( "QLabel { color : rgba(21, 255, 0, 255); }") self.bijspring_title = QtWidgets.QLabel(self) self.bijspring_title.setFont(font) self.bijspring_title.setAlignment(QtCore.Qt.AlignCenter) self.bijspring_title.setText('Verbruiken') self.bijspring_title.setGeometry( QtCore.QRect(int(width * 0.8 - hei[0] * fac_scale / 2), y_pos[2], wid[0] * (1 + fac_scale), hei[0])) self.bijspring_title.setStyleSheet("QLabel {color : red; }") font.setPixelSize(int(height * 0.03)) overhead3 = GraphicsLayoutWidget(self) overhead3.setGeometry( QtCore.QRect(int(width * 0.85), int(y_pos[1] + +0.49 * hei[1]), int(width * 0.05), int(0.02 * hei[1]))) overhead3.setBackground('w') self.h2_slide = QtWidgets.QSlider(self) self.h2_slide.setRange(-100, 100) self.h2_slide.setOrientation(QtCore.Qt.Vertical) self.h2_slide.setGeometry(int(width * 0.8), y_pos[1], wid[0], hei[1]) self.h2_slide.setStyleSheet( """QSlider {background-color: rgba(255, 255, 255, 0)} QSlider::handle:vertical { background: black; margin: 0 -80px; border: 1px solid; height: 10px; } QSlider::groove:vertical { background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 green, stop:1 red); width: 10px; margin: 0 -5px; } """) overhead = GraphicsLayoutWidget(self) overhead.setGeometry( QtCore.QRect(int(width * 0.8), y_pos[1], wid[0], hei[1])) overhead.setBackground(None) overhead2 = overhead.addViewBox(enableMouse=False) overhead2.setBackgroundColor(None) overhead2.setAutoPan(False, False) self.data_manager.h2_slide = self.h2_slide
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( )
class ScopeWindow(QtGui.QMainWindow): def __init__(self, parent=None, maxepisodes=10): super(ScopeWindow, self).__init__(parent) self.episodes = None self.index = [] # set a limit on how many episodes to memorize self.maxepisodes = maxepisodes # Record state of the scope window self.isclosed = True # This keeps track of the indices of which episodes are loaded self._loaded_array = [] # Default options self.options = {'colorfy':False,\ 'layout':[['Voltage', 'A', 0, 0], ['Current', 'A', 1, 0]]} # layout = [Stream, Channel, row, col] # Keep track of which colors have been used self._usedColors = [] # Set up the GUI window self.setupUi(self) self.setDisplayTheme() def setupUi(self, MainWindow): """This function is converted from the .ui file from the designer""" MainWindow.setObjectName(_fromUtf8("Scope Window")) MainWindow.resize(1200, 600) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) # Graphics layout self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget) self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.graphicsLayout = QtGui.QHBoxLayout() self.graphicsLayout.setObjectName(_fromUtf8("graphicsLayout")) self.graphicsView = GraphicsLayoutWidget(self.centralwidget) self.graphicsView.setObjectName(_fromUtf8("graphicsView")) self.graphicsLayout.addWidget(self.graphicsView) self.horizontalLayout.addLayout(self.graphicsLayout) # Side panel layout: initialize as a list view self.sideDockPanel = QtGui.QDockWidget("Settings", self) self.sideDockPanel.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea) self.sideDockPanel.setObjectName(_fromUtf8("sideDockPanel")) self.sideDockPanel.hide() # self.sidePanelLayout = QtGui.QHBoxLayout() # self.sidePanelLayout.setObjectName(_fromUtf8("sidePanelLayout")) self.listView = QtGui.QListView(self.centralwidget) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.listView.sizePolicy().hasHeightForWidth()) self.listView.setSizePolicy(sizePolicy) self.listView.setObjectName(_fromUtf8("listView")) self.sideDockPanel.setWidget(self.listView) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.sideDockPanel) # self.sidePanelLayout.addWidget(self.listView) # self.horizontalLayout.addLayout(self.sidePanelLayout) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1225, 26)) self.menubar.setObjectName(_fromUtf8("menubar")) self.setMenuBarItems() MainWindow.setMenuBar(self.menubar) self.statusbar = QtGui.QStatusBar(MainWindow) self.statusbar.setObjectName(_fromUtf8("statusbar")) MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # ---------------- Additional main window behaviors ----------------------- def setMenuBarItems(self): # File Menu fileMenu = self.menubar.addMenu('&File') # File: Export exportMenu = fileMenu.addMenu('&Export') exportWithScaleBarAction = QtGui.QAction(QtGui.QIcon('export.png'), 'Export with scalebar', self) exportWithScaleBarAction.setShortcut('Ctrl+Alt+E') exportWithScaleBarAction.setStatusTip('Export with scalebar') exportWithScaleBarAction.triggered.connect(self.printme) exportMenu.addAction(exportWithScaleBarAction) # View Menu viewMenu = self.menubar.addMenu('&View') # View: show settings viewMenu.addAction(self.sideDockPanel.toggleViewAction()) # View: Colorfy colorfyAction = QtGui.QAction('Color code traces', self, checkable=True, checked=False) colorfyAction.setShortcut('Ctrl+Alt+C') colorfyAction.setStatusTip('Toggle between color coded traces and black traces') colorfyAction.triggered.connect(lambda: self.toggleTraceColors(colorfyAction.isChecked())) viewMenu.addAction(colorfyAction) def printme(self): print('doing stuff') def closeEvent(self, event): """Override default behavior when closing the main window""" self.isclosed = True def retranslateUi(self, MainWindow): """Set window title and other miscellaneous""" MainWindow.setWindowTitle(_translate(__version__, __version__, None)) # ------------- Episode plotting utilities -------------------------------- def updateEpisodes(self, episodes=None, index=[]): """First compare episodes with self.episodes and index with self.index Only update the difference in the two sets""" if not isinstance(episodes, dict) or not isinstance(self.episodes, dict): bool_old_episode = False else: bool_old_episode = self.episodes['Name'] == episodes['Name'] index_insert = list(set(index) - set(self.index)) index_remove = list(set(self.index) - set(index)) if bool_old_episode and not index_insert and not index_remove: # same episode, same index return elif not bool_old_episode: # new item / cell index_insert = index index_remove = [] self.episodes = episodes self.episodes['Data'] = [[]] * len(self.episodes['Dirs']) self._loaded_array = [] # update index self.index += index_insert for a in index_remove: self.index.remove(a) # Insert new episodes for i in index_insert: self.episodes['Data'][i] = NeuroData(dataFile=self.episodes['Dirs'][i], old=True, infoOnly=False, getTime=True) self._loaded_array.append(i) # call self.drawPlot self.drawEpisode(self.episodes['Data'][i], info=(self.episodes['Name'], self.episodes['Epi'][i])) # Remove episodes for j in index_remove: self.removeEpisode(info=(self.episodes['Name'], self.episodes['Epi'][j])) def drawEpisode(self, zData, info=None, pen=None): """Draw plot from 1 zData""" # Set up pen color if self.options['colorfy']: availableColors = list(colors) for c in self._usedColors: availableColors.remove(c) pen = availableColors[0] self._usedColors.append(pen) elif pen is None: pen = self.options['theme']['pen'] # Loop through all the subplots for n, l in enumerate(self.options['layout']): # get viewbox p = self.graphicsView.getItem(row=l[2], col=l[3]) if p is None: p = self.graphicsView.addPlot(row=l[2], col=l[3]) # Make sure later viewboxes are linked in time domain if n>0: p.setXLink(self.graphicsView.getItem(row=0, col=0)) # put an identifier on the trace if isinstance(info, tuple): pname = info[0]+'.'+info[1]+'.'+l[0]+'.'+l[1] else: pname = None p.plot(x=zData.Time, y=getattr(zData, l[0])[l[1]], pen=pen, name=pname) def removeEpisode(self, info=None): if not info: return for l in self.options['layout']: # get viewbox p1 = self.graphicsView.getItem(row=l[2], col=l[3]) pname = info[0]+'.'+info[1]+'.'+l[0]+'.'+l[1] remove_index = [] for k, a in enumerate(p1.listDataItems()): if a.name() == pname: # matching p1.removeItem(a) remove_index.append(k) # recover the colors if remove_index and self.options['colorfy']: for r in remove_index: del self._usedColors[r] # ----------------------- Layout utilities -------------------------------- def setLayout(self): return # ----------------------- Option utilities ---------------------------------- def toggleTraceColors(self, checked): """Change traces from black to color coded""" # if already painted in color, paint in default pen again if not checked: self.options['colorfy'] = False self._usedColors = [] # reset used colors else: self.options['colorfy'] = True for l in self.options['layout']: # get viewbox p = self.graphicsView.getItem(row=l[2], col=l[3]) for k, a in enumerate(p.listDataItems()): if not checked: pen = self.options['theme']['pen'] else: pen = colors[k%len(colors)] if pen not in self._usedColors: self._usedColors.append(pen) pen = pg.mkPen(pen) a.setPen(pen) def setDisplayTheme(self, theme='whiteboard'): self.options['theme'] = {'blackboard':{'background':'k', 'pen':'w'}, \ 'whiteboard':{'background':'w', 'pen':'k'}\ }.get(theme) self.graphicsView.setBackground(self.options['theme']['background'])
class widget_pl_grid( QWidget ) : #----------------------------------------------------------------------- # DEFINE THE INITIALIZATION FUNCTION. #----------------------------------------------------------------------- def __init__( self, core, n, n_plt_x=None, n_plt_y=None, n_plt=None ) : # Inherit all attributes of an instance of "QWidget". super( widget_pl_grid, self ).__init__( ) # Initialize the counter of repaint events for this widget as # well as a maximum value for this counter. # Note. For some reason, adjusting the individual plots to have # uniform sizes is difficult to achieve before the widget # is rendered. Thus, once a paint event occurs, the # "self.paintEvent( )" function picks it up and makes a # call to "self.ajst_grd( )". This counter and its # maximum value are used ensure that "self.paintEvent( )" # makes such a call only in response to the intial few # painting (so as to prevent an infinite loop). # Note. The first paint seems to be a "dummy" of some sort. # Whatever the case, "self.n_paint_max = 1" seems to # generally be insufficient. self.n_painted = 0 self.n_painted_max = 3 # Disable user events self.setDisabled( True ) self.core = core self.n = n self.t = [] self.delta_t = [] self.time_label = QLabel( ' ' ) self.time_label.setAlignment( Qt.AlignCenter ) self.time_label.setContentsMargins( 0,5,0,0 ) font = QFont( ) font.setBold(True) self.time_label.setFont( font ) # Prepare to respond to signals received from the Janus core. self.connect( self.core, SIGNAL('janus_rset'), self.resp_rset ) self.connect( self.core, SIGNAL('janus_chng_pl_spc'), self.resp_chng_pl_spc ) self.connect( self.core, SIGNAL('janus_chng_mom_pl_sel'), self.resp_chng_mom_pl_sel ) self.connect( self.core, SIGNAL('janus_chng_mom_pl_res'), self.resp_chng_mom_pl_res ) self.connect( self.core, SIGNAL('janus_chng_nln_gss'), self.resp_chng_nln_gss ) self.connect( self.core, SIGNAL('janus_chng_nln_sel_all'), self.resp_chng_nln_sel_all ) self.connect( self.core, SIGNAL('janus_chng_nln_res'), self.resp_chng_nln_res ) self.connect( self.core, SIGNAL('janus_chng_dsp'), self.resp_chng_dsp ) #TODO add more signals # Assign (if not done so already) and store the shape of the # plot-grid array. self.n_plt_x = 5 if ( n_plt_x is None ) else n_plt_x self.n_plt_y = 5 if ( n_plt_y is None ) else n_plt_y if ( n_plt is None ) : self.n_plt = self.n_plt_x * self.n_plt_y # Initizalize the pens, brushes, and fonts used by this widget. self.pen_plt = mkPen( color='k' ) self.pen_hst = mkPen( color='k' ) self.pen_pnt_c = mkPen( color='k' ) self.pen_pnt_y = mkPen( color='k' ) self.pen_pnt_r = mkPen( color='k' ) self.pen_crv_b = mkPen( color='b' ) self.pen_crv_g = mkPen( color='g' ) self.bsh_pnt_c = mkBrush( color='c' ) self.bsh_pnt_y = mkBrush( color='y' ) self.bsh_pnt_r = mkBrush( color='r' ) self.fnt = self.core.app.font( ) # Set the maximum number of velocity channels and the maximum # number of ion species. self.n_k = 14 self.n_ion = self.core.nln_n_pop # Initialize the widget and it's plot's. self.init_plt( ) # Populate the plots with the histograms (and labels), the # selection points, and the fit curves. self.make_hst( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR INITIALIZING THE WIDGET AND ITS PLOTS. #----------------------------------------------------------------------- def init_plt( self ) : # Initialize the "GraphicsLayoutWidget" for this widget. This # will allow a grid of "GraphicsItem" objects, which will # include the plots themselves, the axes, and the axis labels. # Note. The "QGridLayout" object given to this widget as its # layout is essentially a dummy. I tried to just having # this widget be an extention of "GraphicsLayoutWidget" # (i.e., having it inheret that type), but I couldn't get # it to display anything at all. self.setLayout( QGridLayout( ) ) self.grd = GraphicsLayoutWidget( ) self.grd.setBackground( 'w' ) self.layout( ).addWidget( self.time_label ) self.layout( ).addWidget( self.grd ) self.layout().setContentsMargins( 0, 0, 0, 0 ) # Initialize the text for the x- and y-axis labels. Then, # create the labels themselves and add them to the grid. self.txt_axs_x = 'Projected Proton Inflow Velocity [km/s]' self.txt_axs_y = 'Phase-space Density' +\ u'[cm\u00AF\u00B3/(km/s)\u00B3]' if ( self.core.app.res_lo ) : size = '8pt' else : size = '10pt' self.lab_axs_x = LabelItem( self.txt_axs_x, angle=0 , color='b', size=size ) self.lab_axs_y = LabelItem( self.txt_axs_y, angle=270, color='b', size=size ) self.grd.addItem( self.lab_axs_x, self.n_plt_y + 1, 2, 1, self.n_plt_x ) self.grd.addItem( self.lab_axs_y, 0, 0, self.n_plt_y, 1 ) # Initialize the arrays that will contain the individual axes, # plots, and plot elements (i.e., the histograms, fit curves, # labels, and selection points). self.plt = tile( None, [ self.n_plt_y, self.n_plt_x ] ) self.axs_x = tile( None, self.n_plt_x ) self.axs_y = tile( None, self.n_plt_y ) self.hst = tile( None, [ self.n_plt_y, self.n_plt_x ] ) self.lbl = tile( None, [ self.n_plt_y, self.n_plt_x ] ) self.crv = tile( None, [ self.n_plt_y, self.n_plt_x ] ) self.crv_ion = tile( None, [ self.n_plt_y, self.n_plt_x, self.n_ion ] ) self.pnt = tile( None, [ self.n_plt_y, self.n_plt_x, self.n_k ] ) # Initialize the scale-type for each axis, then generate the # (default) axis-limits and adjusted axis-limits. self.log_x = False self.log_y = True self.make_lim( ) # Create, store, and add to the grid the individual axes: first # the horizontal and then the vertical. for i in range( self.n_plt_x ) : self.axs_x[i] = AxisItem( 'bottom', maxTickLength=5 ) self.axs_x[i].setLogMode( self.log_x ) self.axs_x[i].setRange( self.x_lim[0], self.x_lim[1] ) self.axs_x[i].setTickFont( self.fnt ) if ( self.core.app.res_lo ) : self.axs_x[i].setHeight( 10 ) else : self.axs_x[i].setHeight( 20 ) self.grd.addItem( self.axs_x[i], self.n_plt_y, i + 2 ) for j in range( self.n_plt_y ) : self.axs_y[j] = AxisItem( 'left', maxTickLength=5 ) self.axs_y[j].setLogMode( self.log_y ) self.axs_y[j].setRange( self.y_lim[0], self.y_lim[1] ) self.axs_y[j].setTickFont( self.fnt ) if ( self.core.app.res_lo ) : self.axs_y[j].setWidth( 32 ) else : self.axs_y[j].setWidth( 40 ) self.grd.addItem( self.axs_y[j], j, 1 ) # Create, store, and add to the grid the individual plots. # Likewise, create, store, and add to each plot a label. for t in range( self.n_plt_y ) : for p in range( self.n_plt_x ) : # Compute the plot number of this plot. d = p + ( t * self.n_plt_x ) # If creating this plot would exceed the # specified number of plots, don't create it. if ( d >= self.n_plt ) : continue # Create and store this plot, adjust its limits, # and add it to the grid. # Note: locations of plots are inverted along # theta self.plt[t,p] = event_ViewBox( self, border=self.pen_plt, enableMouse=False, enableMenu=False ) self.plt[t,p].setRange( xRange=self.x_lim, yRange=self.y_lim, padding=0. ) self.grd.addItem( self.plt[t,p], self.n_plt_y-t-1, p + 2 ) # Create and store an (empty) label and add it # to this plot. self.lbl[t,p] = TextItem( anchor=(1,0) ) self.lbl[t,p].setFont( self.fnt ) self.plt[t,p].addItem( self.lbl[t,p] ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR GENERATING AXIS-LIMITS (AND ADJUSTED LIMITS). #----------------------------------------------------------------------- def make_lim( self ) : # If no spectrum has been loaded, use the default limits; # otherwise, use the spectral data to compute axis limits. # Note: velocities are recorded in reverse order. if ( self.core.pl_spec_arr == [] ) : self.domain = [ 300. , 900. ] self.range = [ 1.e-10, 1.e-5 ] else : self.domain = [self.core.pl_spec_arr[self.n]['vel_strt'][0], self.core.pl_spec_arr[self.n]['vel_stop'][-1]] arr_psd_flat = [self.core.pl_spec_arr[self.n]['psd_flat'][i] for i in (where(array(self.core.pl_spec_arr[self.n]['psd_flat']) != 0.)[0])] self.range = [ self.core.mom_psd_min, self.core.mom_psd_max ] # Note: psd values are less than 1 if ( self.log_y ) : self.range[0] = self.range[0] ** 1.05 self.range[1] = self.range[1] ** 0.9 else : self.range[1] += 0.1 * ( self.range[1] - self.range[0] ) # Compute the "adjusted limits" for each axis. if ( self.log_x ) : self.x_lim = [ log10( x ) for x in self.domain ] else : self.x_lim = self.domain if ( self.log_y ) : self.y_lim = [ log10( y ) for y in self.range ] else : self.y_lim = self.range #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR CREATING THE PLOTS' HISTOGRAMS (AND LABELS). #----------------------------------------------------------------------- def make_hst( self ) : # Reset the timestamp label self.time_label.setText( ' ' ) # If no spectrum has been loaded, abort. if ( self.core.pl_spec_arr == [] ) : return # If the index of this P-L grid is outside the bounds of the P-L # spectrum currently loaded, abort. if ( self.n >= len( self.core.pl_spec_arr ) ) : return # Generate the timestamp label self.t = self.t + [self.core.pl_spec_arr[self.n]['time'][0]] self.t_0 = self.core.fc_spec['time'] self.delta_t = self.delta_t + [( self.t[-1]- self.t_0 ).total_seconds( )] self.time_label.setText( str(self.t[-1])[0:-7] + ' ' + u'\u0394t = {}'.format( round( self.delta_t[-1], 0) ) + 's' ) # Use the spectral data to compute new axis-limits. self.make_lim( ) for p in range( self.n_plt_x ) : self.axs_x[p].setRange( self.x_lim[0], self.x_lim[1] ) for t in range( self.n_plt_y ) : self.axs_y[t].setRange( self.y_lim[0], self.y_lim[1] ) # Histograms are broken down by phi horizontally and # theta vertically for t in range( self.core.pl_spec_arr[self.n]['n_the'] ): for p in range ( self.core.pl_spec_arr[self.n]['n_phi'] ): # If this plot does not exist, move onto # the next one. if ( self.plt[t,p] is None ) : continue #-----------------------------# #---DATA GENERATION SECTION---# #-----------------------------# # Generate a step function for the # look direction associated with this widget. self.stp = array( [step( self.core.pl_spec_arr[self.n]['vel_cen'], self.core.pl_spec_arr[self.n]['vel_del'], self.core.pl_spec_arr[self.n]['psd'][t][p])]) # Calculate the points to be plotted from the # step function stp_pnt = array( [ array( datum.calc_pnt( lev_min=self.range[0]/2.) ) for datum in self.stp ] ) self.x_set = stp_pnt[:,0][0] self.y_set = stp_pnt[:,1][0] # If plotting log(y) and there are any psd # values of zero, replace those points with an # arbitrary minimum y value if ( self.log_y ) : y_min = self.range[0]/2. self.y_lim[0] = log10(y_min) self.y_set = [ max( y, y_min ) for y in self.y_set ] # If generating a log plot, take the log of the # points to be plotted self.x_pnts = log10( self.x_set ) if ( self.log_x ) else \ self.x_set self.y_pnts = log10( self.y_set ) if ( self.log_y ) else \ self.y_set #---------------------------------# #---GRAPHICS GENERATION SECTION---# #---------------------------------# # If a histogram already exists for this plot, # remove and delete it. if ( self.hst[t,p] is not None ) : self.plt[t,p].removeItem(self.hst[t,p]) self.hst[t,p] = None # Clear this plot's label of text. self.lbl[t,p].setText( '' ) # Adjust this plot's limits and then move it's # label in response. self.plt[t,p].setRange( xRange=self.x_lim, yRange=self.y_lim, padding=0. ) self.lbl[t,p].setPos( self.x_lim[1], self.y_lim[1] ) # Update this plot's label with appropriate text # indicating the pointing direction. elev = round( self.core.pl_spec_arr[self.n]['elev_cen'][t] ) azim = round( self.core.pl_spec_arr[self.n]['azim_cen'][p] ) txt = ( u'({0:+.0f}\N{DEGREE SIGN}, ' + u'{1:+.0f}\N{DEGREE SIGN})' ).format( elev, azim-180 ) self.lbl[t,p].setText( txt, color=(0,0,0) ) # Generate the histogram for the data from this # look direction and display it in the plot. self.hst[t,p] = PlotDataItem( self.x_pnts, self.y_pnts, pen=self.pen_hst ) self.plt[t,p].addItem( self.hst[t,p] ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR CREATING THE PLOTS' SELECTION POINTS. #----------------------------------------------------------------------- def make_pnt( self ) : # If no spectrum has been loaded, abort. if ( self.core.pl_spec_arr == [] ) : return # If the index of this P-L grid is outside the bounds of the P-L # spectrum currently loaded, abort. if ( self.n >= len( self.core.pl_spec_arr ) ) : return # Add selection points to each plot. for d in range( min( self.core.pl_spec_arr[self.n]['n_dir'], self.n_plt ) ) : # Determine the location of this plot within the grid # layout. t = d // self.n_plt_x p = d % self.n_plt_y # If this plot does not exist, move onto the next one. if ( self.plt[t,p] is None ) : continue # Add the selection points to this plot. for b in range( self.core.pl_spec_arr[self.n]['n_bin'] ) : sel_bin = False sel_dir = True sel_alt = None if( self.core.dsp == 'mom' ): sel_bin = self.core.pl_spec_arr[self.n].arr[t][p][b]['mom_sel'] elif ( ( self.core.dsp == 'gsl' or self.core.dsp == 'nln' ) and ( self.core.nln_pl_sel is not None ) ) : sel_bin = self.core.nln_pl_sel[self.n][t][p][b] # elif ( ( self.core.dsp == 'nln' ) and # ( self.core.pl_spec_arr[self.n].nln_res_sel # is not None ) ) : # sel_bin = \ # self.core.nln_pl_sel[t][p][b] # if ( self.core.pl_spec_arr[self.n].nln_sel is None ) : # sel_alt = None # else : # sel_alt = \ # self.core.pl_spec_arr[self.n].nln_sel[t][p][b] self.chng_pnt( t, p, b, sel_bin, sel_alt=sel_alt ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR CHANGING THE VISIBILITY OF A DATUM'S POINTS. #----------------------------------------------------------------------- def chng_pnt( self, t, p, b, sel_bin, sel_alt=None ) : # If no spectrum has been loaded, abort. if ( self.core.pl_spec_arr == [] ) : return # If the index of this P-L grid is outside the bounds of the P-L # spectrum currently loaded, abort. if ( self.n >= len( self.core.pl_spec_arr ) ) : return # If this point already exists, remove it from its plot and # delete it. if ( self.pnt[t,p,b] is not None ) : self.plt[t,p].removeItem( self.pnt[t,p,b] ) self.pnt[t,p,b] = None # If this point was not selected (based on both its primary and # secondary states), return (since there's nothing more to be # done). if ( not sel_bin or self.core.pl_spec_arr[self.n]['psd'][t][p][b] == 0) : return # Determine the "d" index corresponding to this look direction. d = p + ( t * self.n_plt_x ) # Computed the adjusted point location in the "ViewBox". if ( self.log_x ) : ax = log10( self.core.pl_spec_arr[self.n]['vel_cen'][b] ) else : ax = self.core.pl_spec_arr[self.n]['vel_cen'][b] if ( self.log_y ) : ay = log10( self.core.pl_spec_arr[self.n]['psd'][t][p][b] ) else : ay = self.core.pl_spec_arr[self.n]['psd'][t][p][b] # Select the color for the point (i.e., the brush and pen used # to render it) based on whether or not this datum's look # direction has been selected and whether or not the primary and # secondary selection states match. # if ( sel_bin == sel_alt ) : pen = self.pen_pnt_c brush = self.bsh_pnt_c # else : # pen = self.pen_pnt_y # brush = self.bsh_pnt_y # else : # pen = self.pen_pnt_r # brush = self.bsh_pnt_r # Select the symbol based on the values of the primary and # secondary selection states. # Note. At this point in the code, at least one of these two # states must be "True" since this -- when both states # are "False", this function returns before it reaches # this point. if ( sel_bin ) : symbol = 'o' else : symbol = 't' # Create, store, and add this selection point to the plot. if ( self.core.app.res_lo ) : size = 3 else : size = 6 self.pnt[t,p,b] = PlotDataItem( [ax], [ay], symbol=symbol, symbolSize=size, symbolPen=pen, symbolBrush=brush ) self.plt[t,p].addItem( self.pnt[t,p,b] ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR CREATING THE PLOTS' FIT CURVES. #----------------------------------------------------------------------- def make_crv( self ) : # If no "list" of "p" index-values has been provided by the # user, assume that the curves in all plots should be # (re-)rendered. if ( self.core.pl_spec_arr == [] ) : return # If the index of this P-L grid is outside the bounds of the P-L # spectrum currently loaded, abort. if ( self.n >= len( self.core.pl_spec_arr ) ) : return # Return the "nln_psd_gss_ion axes to their original order. if( self.core.nln_psd_gss_ion is not None ) : if( self.core.nln_psd_gss_ion != [ ] ) : nln_psd_gss_ion = [ [ [ [ [ self.core.nln_psd_gss_ion[n][t][f][b][p] for b in range( self.core.pl_spec_arr[n]['n_bin'] ) ] for f in range( self.core.pl_spec_arr[n]['n_phi'] ) ] for t in range( self.core.pl_spec_arr[n]['n_the'] ) ] for n in range( len( self.core.pl_spec_arr ) ) ] for p in range( self.core.nln_gss_n_pop ) ] # Return the "nln_res_psd_ion axes to their original order. if( self.core.nln_res_psd_ion is not None ) : if( self.core.nln_res_psd_ion != [ ] ) : nln_res_psd_ion = [ [ [ [ [ self.core.nln_res_psd_ion[n][t][f][b][p] for b in range( self.core.pl_spec_arr[n]['n_bin'] ) ] for f in range( self.core.pl_spec_arr[n]['n_phi'] ) ] for t in range( self.core.pl_spec_arr[n]['n_the'] ) ] for n in range( len( self.core.pl_spec_arr ) ) ] for p in range( self.core.nln_gss_n_pop ) ] # For each plot in the grid, generate and display a fit curve # based on the results of the analysis. vel_cen = self.core.pl_spec_arr[self.n]['vel_cen'] for t in range( self.core.pl_spec_arr[self.n]['n_the'] ) : for p in range( self.core.pl_spec_arr[self.n]['n_phi'] ) : # If this plot does not exist, move onto the next grid # element. if ( self.plt[t,p] is None ) : continue # If any curves already exist for this plot, remove and # delete them. if ( self.crv[t,p] is not None ) : self.plt[t,p].removeItem( self.crv[t,p] ) self.crv[t,p] = None for n in range( self.n_ion ) : if ( self.crv_ion[t,p,n] is not None ) : self.plt[t,p].removeItem( self.crv_ion[t,p,n] ) self.crv_ion[t,p,n] = None # Create and add the curve of the indiviadual # contributions to the modeled psd to the plot. for n in range( ( 1 if self.core.dsp == 'mom' else self.core.nln_gss_n_pop ) ) : # Extract the points for this fit curve. x = array( vel_cen ) if( self.core.dsp == 'mom' ) : y = array( self.core.pl_spec_arr[self.n]['psd_mom'][t][p] ) elif( self.core.dsp == 'gsl' ) : y = array( nln_psd_gss_ion[n][self.n][t][p] ) elif( self.core.dsp == 'nln' ) : y = array( nln_res_psd_ion[n][self.n][t][p] ) # If any points are 0 or None, set them # to an arbitrary minimum value for tk in range(len(y)): if ( ( y[tk] == 0 ) or ( y[tk] is None ) ) : y[tk] = 1e-20 if ( self.log_x ) : ax = log10( x ) else : ax = x if ( self.log_y ) : ay = array( [ log10( v ) for v in y ] ) else : ay = y # Create, store, and add to the plot # this fit curve. self.crv_ion[t,p,n] = PlotDataItem( ax, ay, pen=( self.pen_crv_b if self.core.dsp=='mom' else self.pen_crv_g ) ) self.plt[t,p].addItem( self.crv_ion[t,p,n] ) # If applicable, create and add the curve of the # total contributions to the modeled psd to the # plot if( self.core.dsp == 'gsl' ) : x = array( vel_cen ) y = array( self.core.nln_psd_gss_tot[self.n][t][p] ) # If any points are 0 or None, set them # to an arbitrary minimum value for tk in range(len(y)): if ( ( y[tk] == 0 ) or ( y[tk] is None ) ) : y[tk] = 1e-20 if ( self.log_x ) : ax = log10( x ) else : ax = x if ( self.log_y ) : ay = array( [ log10( v ) for v in y ] ) else : ay = y # Create, store, and add to the plot # this fit curve. self.crv[t,p] = PlotDataItem( ax, ay, pen=( self.pen_crv_b ) ) self.plt[t,p].addItem( self.crv[t,p] ) # If applicable, create and add the curve of the # total contributions to the non-linear psd to # the plot if( ( self.core.dsp == 'nln' ) and ( self.core.nln_res_psd_tot is not None ) ) : x = array( vel_cen ) y = array( self.core.nln_res_psd_tot[self.n][t][p] ) # If any points are 0 or None, set them # to an arbitrary minimum value for tk in range(len(y)): if ( ( y[tk] == 0 ) or ( y[tk] is None ) ) : y[tk] = 1e-20 if ( self.log_x ) : ax = log10( x ) else : ax = x if ( self.log_y ) : ay = array( [ log10( v ) for v in y ] ) else : ay = y # Create, store, and add to the plot # this fit curve. self.crv[t,p] = PlotDataItem( ax, ay, pen=( self.pen_crv_b ) ) self.plt[t,p].addItem( self.crv[t,p] ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESETTING THE PLOTS' HISTOGRAMS (AND LABELS). #----------------------------------------------------------------------- def rset_hst( self, rset_lbl=False ) : self.time_label.setText( '' ) self.t = [] self.delta_t = [] # For each plot that exists in the grid, remove and delete it's # histogram. Likewise, if requested, empty it's label (but # still leave the label itself intact). for t in range( self.n_plt_y ) : for p in range( self.n_plt_x ) : # If the plot does not exist, move onto the the # next one. if ( self.plt[t,p] is None ) : continue # If a histogram exists for this plot, remove # and delete it. if ( self.hst[t,p] is not None ) : self.plt[t,p].removeItem( self.hst[t,p] ) self.hst[t,p] = None # If requested, reset this plot's label text to # the empty string. if ( rset_lbl ) : self.lbl[t,p].setText( '', color=(0,0,0) ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESETTING THE PLOTS' SELECTION POINTS. #----------------------------------------------------------------------- def rset_pnt( self ) : # For each plot that exists in the grid, hide and remove its # selection points. for t in range( self.n_plt_y ) : for p in range( self.n_plt_x ) : # If the plot does not exist, move onto the the # next grid element. if ( self.plt[t,p] is None ) : continue # Remove and then delete each of this plot's # selection points. for b in range( self.n_k ) : if ( self.pnt[t,p,b] is not None ) : self.plt[t,p].removeItem( self.pnt[t,p,b] ) self.pnt[t,p,b] = None #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESETTING THE PLOTS' FIT CURVES. #----------------------------------------------------------------------- def rset_crv( self ) : # For each plot that exists in the grid, remove and delete its # fit curves. for t in range( self.n_plt_y ) : for p in range( self.n_plt_x ) : # If the plot does not exist, move onto the the # next one. if ( self.plt[t,p] is None ) : continue # Remove and delete this plot's fit curve. if ( self.crv[t,p] is not None ) : self.plt[t,p].removeItem( self.crv[t,p] ) self.crv[t,p] = None for n in range( self.n_ion ) : if ( self.crv_ion[t,p,n] is not None ) : self.plt[t,p].removeItem( self.crv_ion[t,p,n] ) self.crv_ion[t,p,n] = None #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "rset" SIGNAL. #----------------------------------------------------------------------- def resp_rset( self ) : # Clear the plots of all their elements. self.rset_hst( ) self.rset_pnt( ) self.rset_crv( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_spc" SIGNAL. #----------------------------------------------------------------------- def resp_chng_pl_spc( self ) : # Clear the plots of all their elements and regenerate them. self.rset_crv( ) self.rset_pnt( ) self.rset_hst( ) self.make_hst( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_pl_res" SIGNAL. #----------------------------------------------------------------------- def resp_chng_mom_pl_sel( self ) : # If the results of the moments analysis are being displayed, # reset any existing fit curves and make new ones. self.make_pnt( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_mom_pl_res" SIGNAL. #----------------------------------------------------------------------- def resp_chng_mom_pl_res( self ) : # If the results of the moments analysis are being displayed, # reset any existing fit curves and make new ones. self.make_crv( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_gss" SIGNAL. #----------------------------------------------------------------------- def resp_chng_nln_gss( self ) : # If the initial guess for the non-linear analysis is being # displayed, reset any existing fit curves and make new ones. if ( self.core.dsp == 'gsl' ) : self.make_crv( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_nln_sel_all" SIGNAL. #----------------------------------------------------------------------- def resp_chng_nln_sel_all( self ) : # If the point selection for the non-linear analysis is being # displayed, reset any existing selection points and create new # ones. if ( ( self.core.dsp == 'gsl' ) or ( self.core.dsp == 'nln' ) ) : self.make_pnt( ) # self.make_crv( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_dsp" SIGNAL. #----------------------------------------------------------------------- def resp_chng_dsp( self ) : # Reset the selection points and fit curves. self.make_pnt( ) self.make_crv( ) #----------------------------------------------------------------------- # DEFINE THE FUNCTION FOR RESPONDING TO THE "chng_dsp" SIGNAL. #----------------------------------------------------------------------- def resp_chng_nln_res( self ) : # Reset the fit curves. self.make_crv( ) '''
class CustomGraphicsLayoutWidget(GraphicsLayoutWidget): def __init__(self, nName: tuple = ("Temperature", "Heater Power"), nUnit: tuple = ("degC", "%P"), parent=None): assert len(nName) == len(nUnit) pyqtgraph.setConfigOption('background', 'w') pyqtgraph.setConfigOption('foreground', 'k') super(CustomGraphicsLayoutWidget, self).__init__(parent) self.nName = nName self.nUnit = nUnit self.curves = [] self.graphs = [] self.legends = [] self._samples = DEFAULT_SAMPLES self._plt = GraphicsLayoutWidget() def set_mode(self, mode): if mode == "Manual": self.is_manmode = True else: self.is_manmode = False self._clear_plot() self._configure_plot() def _clear_plot(self): self.clear() #this is crucial fiuhh self.curves = [] self.graphs = [] def _configure_plot(self): n = len(self.nName) npos = np.linspace(1, n, n) if self.is_manmode: self.nLine = 1 self.legend = MANUAL_LEGEND else: self.nLine = 2 self.legend = PID_LEGEND for name, ypos, unit in zip(self.nName, npos, self.nUnit): self._plt.setBackground(background=None) self._plt.setAntialiasing(True) if name == self.nName[-1]: graph = self.addPlot(labels={ 'right': name, 'bottom': "Waktu (detik)" }) else: graph = self.addPlot(labels={'right': name}) for i in range(self.nLine): curve = [graph.plot()] self.curves.extend(curve) graph.setLabel('right', name, unit) self.graphs.append(graph) self.nextRow() def get_curves(self): print("original curves: {}".format(self.curves)) return self.curves def get_graphs(self): print("original graphs: {}".format(self.graphs)) return self.graphs def get_legend(self): return self.legends
class mainWindow(QMainWindow): # Metodo constructor de la clase def __init__(self): #Inicia el objeto QMainWindow QMainWindow.__init__(self) #carga la configuracion del archivo .ui en el objeto loadUi("mainWindowPPG.ui", self) # Loads everything about mainWindowPPG configuration self.setupUI() # Shared variables, initial values self.queue = Queue(N_SAMPLES) self.dataR = deque([], maxlen=N_SAMPLES) self.dataIR = deque([], maxlen=N_SAMPLES) self.TIME = deque([], maxlen=N_SAMPLES) self._plt = None self._timer_plot = None self.plot_colors = ['#0072bd', '#d95319'] # configures self._configure_plot() self._configure_timers() self._configure_signals() # Loads everything about mainWindowPPG configuration def setupUI(self): """ Configures everything about the mainWindow """ self.plt = GraphicsLayoutWidget( self.centralwidget) # Bringing my plot wiindow as plt self.plt.setAutoFillBackground(False) self.plt.setStyleSheet("border: 0px;") self.plt.setFrameShape(QtWidgets.QFrame.StyledPanel) self.plt.setFrameShadow(QtWidgets.QFrame.Plain) self.plt.setLineWidth(0) self.Layout_graphs.addWidget(self.plt, 0, 0, 1, 1) # Set the plotting squared graph def _configure_plot(self): """ Configures specific elements of the PyQtGraph plots. :return: """ self.plt.setBackground(background=None) self.plt.setAntialiasing(True) self._plt = self.plt.addPlot(row=1, col=1) self._plt.setLabel('bottom', "Time", "s") pass def _configure_timers(self): """ Configures specific elements of the QTimers. :return: """ self._timer_plot = QtCore.QTimer( self) # gives _timer_plot the attribute of QtCore.QTimer self._timer_plot.timeout.connect( self._update_plot) # connects with _update_plot method pass def _update_plot(self): """ Updates and redraws the graphics in the plot. This function us connected to the timeout signal of a QTimer. :return: """ # Spo2 signal parameters f = 2 amp1 = 0.5 # amplitud for Sine signal zeroDes1 = 0.5413 # Desplacement from zero for Sine signal amp2 = 0.5 # amplitud for Cosine signal zeroDes2 = 1.5413 # Desplacement from zero for Cosine signal # generate the time tsignal = time() - self.timestamp # Sine signal function sR = zeroDes1 + amp1 * 0.8 * np.sin(2 * np.pi * tsignal * 3 * f) # Cosine signal function sIR = zeroDes2 + amp2 * 0.8 * np.cos(2 * np.pi * tsignal * 3 * f) # put the data generate (time & signal) into queue self.queue.put([tsignal, sR, sIR]) # get the data generate into queue data = self.queue.get(True, 1) # store data into variables self.TIME.append(data[0]) self.dataR.append(data[1]) self.dataIR.append(data[2]) # Draw new data self._plt.clear() self._plt.plot(x=list(self.TIME)[-PLOT_UPDATE_POINTS:], y=list(self.dataR)[-PLOT_UPDATE_POINTS:], pen=self.plot_colors[1]) self._plt.plot(x=list(self.TIME)[-PLOT_UPDATE_POINTS:], y=list(self.dataIR)[-PLOT_UPDATE_POINTS:], pen=self.plot_colors[0]) def _configure_signals(self): """ Configures the connections between signals and UI elements. :return: """ self.startButton.clicked.connect(self.start) self.stopButton.clicked.connect(self.stop) def start(self): """ Starts the acquisition of the selected serial port. This function is connected to the clicked signal of the Start button. :return: """ self.timestamp = time() self._timer_plot.start(16) def stop(self): """ Stops the acquisition of the selected serial port. This function is connected to the clicked signal of the Stop button. :return: """ self._timer_plot.stop() # stop the Qt timer self.reset_buffers() # Go to reset the vector containing values def reset_buffers(self): self.dataR.clear() self.dataIR.clear() self.TIME.clear()
class Ui_MainWindow(object): def variables(self): self.D1_='D1' self.D2_='D2' self.D3_='D3' self.AVF_='AVF' self.AVR_='AVR' self.AVL_='AVL' self.GENRAL_='GENRAL' def setupUi(self, MainWindow): try: base_path= sys._MEIPASS except Exception: base_path=os.path.abspath(".") path1 = os.path.join(base_path, "imagen1.jpeg") path2 = os.path.join(base_path, "imagen2.jpeg") MainWindow.setObjectName("MainWindow") MainWindow.resize(1350, 747) #MainWindow.setStyleSheet("background-color: blue;") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButtonAbrir = QtWidgets.QPushButton(self.centralwidget) self.pushButtonAbrir.setGeometry(QtCore.QRect(280, 10, 300, 32)) self.pushButtonAbrir.setObjectName("pushButtonAbrir") #self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) #self.pushButton_2.setGeometry(QtCore.QRect(510, 90, 151, 41)) #self.pushButton_2.setObjectName("pushButton_2") self.graphicsView = GraphicsLayoutWidget(self.centralwidget) self.graphicsView.setGeometry(QtCore.QRect(750, 230, 585, 370)) self.graphicsView.setObjectName("graphicsView") #self.graphicsView.setBackground(background=None) self.label_7 = QtWidgets.QLabel(self.centralwidget) self.label_7.setGeometry(QtCore.QRect(1050, 1, 300, 100)) self.label_7.setObjectName("label_7") pixmap = QPixmap(path1) self.label_7.setPixmap(pixmap) self.label_8 = QtWidgets.QLabel(self.centralwidget) self.label_8.setGeometry(QtCore.QRect(800, 1, 300, 100)) self.label_8.setObjectName("label_8") pixmap = QPixmap(path2) self.label_8.setPixmap(pixmap) #Persona que creo el programa self.label_9 = QtWidgets.QLabel(self.centralwidget) self.label_9.setGeometry(QtCore.QRect(1000, 630, 2000, 70)) self.label_9.setObjectName("label_9") #Nombre del proyecto self.label_10 = QtWidgets.QLabel(self.centralwidget) self.label_10.setGeometry(QtCore.QRect(1000, 595, 2000, 70)) self.label_10.setObjectName("label_10") #Parametros de la persona self.label_nom = QtWidgets.QLabel(self.centralwidget) self.label_nom.setGeometry(QtCore.QRect(800, 20, 800, 200)) self.label_nom.setObjectName("label_nom") self.label_edad = QtWidgets.QLabel(self.centralwidget) self.label_edad.setGeometry(QtCore.QRect(800, 60, 800, 200)) self.label_edad.setObjectName("label_edad") self.label_sexo = QtWidgets.QLabel(self.centralwidget) self.label_sexo.setGeometry(QtCore.QRect(800, 100, 800, 200)) self.label_sexo.setObjectName("label_sexo") self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.groupBox.setGeometry(QtCore.QRect(20, 40, 675, 841)) self.groupBox.setObjectName("groupBox") self.graphicD1 = GraphicsLayoutWidget(self.groupBox) self.graphicD1.setObjectName("graphicD1") self.graphicD1.setGeometry(QtCore.QRect(65, 30, 1000, 110)) self.graphicD1.setBackground(background=None) self.graphicD2 = GraphicsLayoutWidget(self.groupBox) self.graphicD2.setObjectName("graphicD2") self.graphicD2.setGeometry(QtCore.QRect(65, 130, 1000, 110)) self.graphicD2.setBackground(background=None) self.graphicD3 = GraphicsLayoutWidget(self.groupBox) self.graphicD3.setObjectName("graphicD3") self.graphicD3.setGeometry(QtCore.QRect(65, 230, 1000, 110)) self.graphicD3.setBackground(background=None) self.graphicD3_2 = GraphicsLayoutWidget(self.groupBox) self.graphicD3_2.setObjectName("graphicD3_2") self.graphicD3_2.setGeometry(QtCore.QRect(65, 330, 1000, 110)) self.graphicD3_2.setBackground(background=None) self.graphicD3_3 = GraphicsLayoutWidget(self.groupBox) self.graphicD3_3.setGeometry(QtCore.QRect(65, 430, 1000, 110)) self.graphicD3_3.setObjectName("graphicD3_3") self.graphicD3_3.setBackground(background=None) self.graphicD3_4 = GraphicsLayoutWidget(self.groupBox) self.graphicD3_4.setObjectName("graphicD3_4") self.graphicD3_4.setGeometry(QtCore.QRect(65, 530, 1000, 110)) self.graphicD3_4.setBackground(background=None) self.label = QtWidgets.QLabel(self.groupBox) self.label.setGeometry(QtCore.QRect(10, 65, 50, 24)) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.groupBox) self.label_2.setGeometry(QtCore.QRect(10, 165, 50, 24)) self.label_2.setObjectName("label_2") self.label_3 = QtWidgets.QLabel(self.groupBox) self.label_3.setGeometry(QtCore.QRect(10, 265, 50, 24)) self.label_3.setObjectName("label_3") self.label_4 = QtWidgets.QLabel(self.groupBox) self.label_4.setGeometry(QtCore.QRect(10, 365, 60, 24)) self.label_4.setObjectName("label_4") self.label_5 = QtWidgets.QLabel(self.groupBox) self.label_5.setGeometry(QtCore.QRect(10, 465, 60, 24)) self.label_5.setObjectName("label_5") self.label_6 = QtWidgets.QLabel(self.groupBox) self.label_6.setGeometry(QtCore.QRect(10, 565, 60, 24)) self.label_6.setObjectName("label_6") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 863, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) self.pushButtonAbrir.clicked.connect(self.mybutton_clicked) #self.pushButton_2.clicked.connect(self.generatedReport) #Cajas de texto self.line_nom = QtWidgets.QLineEdit(self.centralwidget) self.line_nom.resize(200, 32) self.line_nom.move(875, 100) self.line_edad = QtWidgets.QLineEdit(self.centralwidget) self.line_edad.resize(200, 32) self.line_edad.move(875, 140) #self.line_sexo = QtWidgets.QLineEdit(self.centralwidget) #self.line_sexo.resize(200, 32) #self.line_sexo.move(875, 180) self.combo_sexo = QtWidgets.QComboBox(self.centralwidget) self.combo_sexo.resize(200, 32) self.combo_sexo.move(875, 180) self.combo_sexo.addItems(["None","Male","Female" ]) QtCore.QMetaObject.connectSlotsByName(MainWindow) def mybutton_clicked(self): try: self.variables() #Nombre de encabezados del archivo CSV persona = {"Nombre":self.line_nom.text(),"Edad":self.line_edad.text(),"Genero":self.combo_sexo.currentText()} combo_textt =self.combo_sexo.currentText() #print(combo_textt) filename= QtWidgets.QFileDialog.getOpenFileName() df = pandas.read_csv(filename[0]) x_max=df['x'].max() a=(df["x"])/4 b= (df["x"]+x_max)/4 c= (df["x"]+(2*x_max))/4 d= (df["x"]+(3*x_max))/4 r = pandas.concat([a,b,c,d]) s= pandas.concat([df[self.D1_],df[self.D1_],df[self.D1_],df[self.D1_]]) t= pandas.concat([df[self.D2_],df[self.D2_],df[self.D2_],df[self.D2_]]) u= pandas.concat([df[self.D3_],df[self.D3_],df[self.D3_],df[self.D3_]]) v= pandas.concat([df[self.AVF_],df[self.AVF_],df[self.AVF_],df[self.AVF_]]) w= pandas.concat([df[self.AVR_],df[self.AVR_],df[self.AVR_],df[self.AVR_]]) x= pandas.concat([df[self.AVL_],df[self.AVL_],df[self.AVL_],df[self.AVL_]]) y= pandas.concat([df[self.GENRAL_],df[self.GENRAL_],df[self.GENRAL_],df[self.GENRAL_]]) df = pandas.DataFrame({"x":r, "D1":s,"D2":t,"D3":u,"AVF":v,"AVR":w,"AVL":x,"GENRAL":y}) self.d1_INTERVAL_1=df.query('x >= 3.03 & x <= 3.08')#st self.d1_INTERVAL_2=df.query('x >= 1.7 & x <= 1.9')#t self.d1_INTERVAL_3=df.query('x >= 4.2 & x <= 4.3')#p self.d1_INTERVAL_1_MAX= self.d1_INTERVAL_1[self.D1_].max() self.d1_INTERVAL_2_MAX= self.d1_INTERVAL_2[self.D1_].max() self.d1_INTERVAL_3_MAX= self.d1_INTERVAL_3[self.D1_].max() self.d2_INTERVAL_1=df.query('x >= 15.4 & x <= 15.44')#ST self.d2_INTERVAL_2=df.query('x >= 16.2 & x <= 16.4')#T self.d2_INTERVAL_3=df.query('x >= 16.6 & x <= 16.7')#P self.d2_INTERVAL_1_MAX= self.d2_INTERVAL_1[self.D2_].max() self.d2_INTERVAL_2_MAX= self.d2_INTERVAL_2[self.D2_].max() self.d2_INTERVAL_3_MAX= self.d2_INTERVAL_3[self.D2_].max() self.d3_INTERVAL_1=df.query('x >= 67.01 & x <= 67.05')#st self.d3_INTERVAL_2=df.query('x >= 49.85 & x <= 50')#t self.d3_INTERVAL_3=df.query('x >= 50.35 & x <= 50.45')#p self.d3_INTERVAL_1_MAX= self.d3_INTERVAL_1[self.D3_].max() self.d3_INTERVAL_2_MAX= self.d3_INTERVAL_2[self.D3_].max() self.d3_INTERVAL_3_MAX= self.d3_INTERVAL_3[self.D3_].max() self.avf_INTERVAL_1=df.query('x >= 111.635 & x <= 111.7')#st self.avf_INTERVAL_2=df.query('x >= 113.82 & x <= 114')#t self.avf_INTERVAL_3=df.query('x >= 153.4 & x <= 153.545')#p self.avf_INTERVAL_1_MAX= self.avf_INTERVAL_1[self.AVF_].max() self.avf_INTERVAL_2_MAX= self.avf_INTERVAL_2[self.AVF_].max() self.avf_INTERVAL_3_MAX= self.avf_INTERVAL_3[self.AVF_].max() self.avr_INTERVAL_1=df.query('x >= 99.27 & x <= 99.29')#st self.avr_INTERVAL_2=df.query('x >= 102.06& x <= 102.26')#t self.avr_INTERVAL_3=df.query('x >= 105.95 & x <= 106.09')#p self.avr_INTERVAL_1_MAX= self.avr_INTERVAL_1[self.AVR_].min() self.avr_INTERVAL_2_MAX= self.avr_INTERVAL_2[self.AVR_].min() self.avr_INTERVAL_3_MAX= self.avr_INTERVAL_3[self.AVR_].min() self.avl_INTERVAL_1=df.query('x >= 95.93 & x <= 96.12')#st self.avl_INTERVAL_2=df.query('x >= 104.75 & x <= 104.8')#t self.avl_INTERVAL_3=df.query('x >= 130.67 & x <= 130.81')#p self.avl_INTERVAL_1_MAX= self.avl_INTERVAL_1[self.AVL_].max() self.avl_INTERVAL_2_MAX= self.avl_INTERVAL_2[self.AVL_].max() self.avl_INTERVAL_3_MAX= self.avl_INTERVAL_3[self.AVL_].max() #VALORES ST Y T values_ST_T ={ self.D1_: { "d1_INTERVAL_1_MAX":self.d1_INTERVAL_1_MAX, "d1_INTERVAL_2_MAX":self.d1_INTERVAL_2_MAX, "d1_INTERVAL_3_MAX":self.d1_INTERVAL_3_MAX }, self.D2_: { "d2_INTERVAL_1_MAX":self.d2_INTERVAL_1_MAX, "d2_INTERVAL_2_MAX":self.d2_INTERVAL_2_MAX, "d2_INTERVAL_3_MAX":self.d2_INTERVAL_3_MAX }, self.D3_: { "d3_INTERVAL_1_MAX":self.d3_INTERVAL_1_MAX, "d3_INTERVAL_2_MAX":self.d3_INTERVAL_2_MAX, "d3_INTERVAL_3_MAX":self.d3_INTERVAL_3_MAX }, self.AVF_: { "avf_INTERVAL_1_MAX":self.avf_INTERVAL_1_MAX, "avf_INTERVAL_2_MAX":self.avf_INTERVAL_2_MAX, "avf_INTERVAL_3_MAX":self.avf_INTERVAL_3_MAX }, self.AVR_: { "avr_INTERVAL_1_MAX":self.avr_INTERVAL_1_MAX, "avr_INTERVAL_2_MAX":self.avr_INTERVAL_2_MAX, "avr_INTERVAL_3_MAX":self.avr_INTERVAL_3_MAX }, self.AVL_: { "avl_INTERVAL_1_MAX":self.avl_INTERVAL_1_MAX, "avl_INTERVAL_2_MAX":self.avl_INTERVAL_2_MAX, "avl_INTERVAL_3_MAX":self.avl_INTERVAL_3_MAX, } } #Intervalo general limit=16 GENER_INTERVAL=df.query('x >= 236 & x <= 243') print(GENER_INTERVAL) contPuls=0 bandera = True for index, row in GENER_INTERVAL.iterrows(): if int(row[self.GENRAL_]) >= limit and bandera==True: contPuls = contPuls + 1 bandera = False elif int(row[self.GENRAL_])<limit and bandera == False: contPuls = contPuls + 1 bandera = True #Graficar valores self.graphicD1.plot(x=df['x'], y=df[self.D1_], pen='#2196F3') self.graphicD2.plot(x=(df['x']), y=df[self.D2_], pen='#2196F3') self.graphicD3.plot(x=(df['x']), y=df[self.D3_], pen='#2196F3') self.graphicD3_2.plot(x=(df['x']), y=df[self.AVF_], pen='#2196F3') self.graphicD3_3.plot(x=(df['x']), y=df[self.AVR_], pen='#2196F3') self.graphicD3_4.plot(x=(df['x']), y=df[self.AVL_], pen='#2196F3') self.graphicsView.plot(x=(df['x']), y=df[self.GENRAL_], pen='#2196F3') self.graphicsView.setLabel("bottom", "Time / s") self.generatedReport(df,persona,values_ST_T,contPuls/2) except NameError: print("error: "+NameError) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "RECAHOLT")) MainWindow.setWindowIcon(QtGui.QIcon('ico.png')) self.pushButtonAbrir.setText(_translate("MainWindow", "Open file and report generator")) #self.pushButton_2.setText(_translate("MainWindow", "Generar Reporte")) self.label_9.setText(_translate("MainWindow", "by Jonathan Recalde")) self.label_9.setFont(QtGui.QFont('Times', 20)) self.label_10.setText(_translate("MainWindow", "RECAHOLT")) self.label_10.setFont(QtGui.QFont('Times', 20)) self.groupBox.setTitle(_translate("MainWindow", "Graphics")) self.groupBox.setFont(QtGui.QFont('Times', 20)) self.label.setText(_translate("MainWindow", "D1")) self.label_2.setText(_translate("MainWindow", "D2")) self.label_3.setText(_translate("MainWindow", "D3")) self.label_4.setText(_translate("MainWindow", "aVF")) self.label_5.setText(_translate("MainWindow", "aVR")) self.label_6.setText(_translate("MainWindow", "aVL")) self.label_nom.setText(_translate("MainWindow", "Name:")) self.label_edad.setText(_translate("MainWindow", "Age:")) self.label_sexo.setText(_translate("MainWindow", "Gender:")) self.graphicD1 = self.graphicD1.addPlot(row=1, col=1) self.graphicD2 = self.graphicD2.addPlot(row=1, col=1) self.graphicD3 = self.graphicD3.addPlot(row=1, col=1) self.graphicD3_2 = self.graphicD3_2.addPlot(row=1, col=1) self.graphicD3_3 = self.graphicD3_3.addPlot(row=1, col=1) self.graphicD3_4 = self.graphicD3_4.addPlot(row=1, col=1) self.graphicsView = self.graphicsView.addPlot(row=1, col=1) def generatedReport(self,df,persona,values_ST_T,contPuls): #Valores D1 D1_max= df[self.D1_].max() Time_D1=df.query("D1 == '{0}'".format(D1_max)) int_timeD1= float(Time_D1["x"].values[0]) ST_D1= values_ST_T[self.D1_]['d1_INTERVAL_1_MAX'] Time_ST_D1=self.d1_INTERVAL_1.query("D1 == '{0}'".format(ST_D1)) int_time_ST_D1= float(Time_ST_D1["x"].values[0]) T_D1= values_ST_T[self.D1_]['d1_INTERVAL_2_MAX'] Time_T_D1=self.d1_INTERVAL_2.query("D1 == '{0}'".format(T_D1)) int_time_T_D1= float(Time_T_D1["x"].values[0]) P_D1= values_ST_T[self.D1_]['d1_INTERVAL_3_MAX'] Time_P_D1=self.d1_INTERVAL_3.query("D1 == '{0}'".format(P_D1)) int_time_P_D1= float(Time_P_D1["x"].values[0]) #Valores D2 D2_max= df[self.D2_].max() Time_D2=df.query("D2 == '{0}'".format(D2_max)) int_timeD2= float(Time_D2["x"].values[0]) ST_D2= values_ST_T[self.D2_]['d2_INTERVAL_1_MAX'] Time_ST_D2=self.d2_INTERVAL_1.query("D2 == '{0}'".format(ST_D2)) int_time_ST_D2= float(Time_ST_D2["x"].values[0]) T_D2= values_ST_T[self.D2_]['d2_INTERVAL_2_MAX'] Time_T_D2=self.d2_INTERVAL_2.query("D2 == '{0}'".format(T_D2)) int_time_T_D2= float(Time_T_D2["x"].values[0]) P_D2= values_ST_T[self.D2_]['d2_INTERVAL_3_MAX'] Time_P_D2=self.d2_INTERVAL_3.query("D2 == '{0}'".format(P_D2)) int_time_P_D2= float(Time_P_D2["x"].values[0]) #Valores D3 D3_max= df[self.D3_].max() Time_D3=df.query("D3 == '{0}'".format(D3_max)) int_timeD3= float(Time_D3["x"].values[0]) ST_D3= values_ST_T[self.D3_]['d3_INTERVAL_1_MAX'] Time_ST_D3=self.d3_INTERVAL_1.query("D3 == '{0}'".format(ST_D3)) int_time_ST_D3= float(Time_ST_D3["x"].values[0]) T_D3= values_ST_T[self.D3_]['d3_INTERVAL_2_MAX'] Time_T_D3=self.d3_INTERVAL_2.query("D3 == '{0}'".format(T_D3)) int_time_T_D3= float(Time_T_D3["x"].values[0]) P_D3= values_ST_T[self.D3_]['d3_INTERVAL_3_MAX'] Time_P_D3=self.d3_INTERVAL_3.query("D3 == '{0}'".format(P_D3)) int_time_P_D3= float(Time_P_D3["x"].values[0]) #Valores AVF AVF_max= df[self.AVF_].max() Time_AVF=df.query("AVF == '{0}'".format(AVF_max)) int_timeAVF= float(Time_AVF["x"].values[0]) ST_AVF= values_ST_T[self.AVF_]['avf_INTERVAL_1_MAX'] Time_ST_AVF=self.avf_INTERVAL_1.query("AVF == '{0}'".format(ST_AVF)) int_time_ST_AVF= float(Time_ST_AVF["x"].values[0]) T_AVF= values_ST_T[self.AVF_]['avf_INTERVAL_2_MAX'] Time_T_AVF=self.avf_INTERVAL_2.query("AVF == '{0}'".format(T_AVF)) int_time_T_AVF= float(Time_T_AVF["x"].values[0]) P_AVF= values_ST_T[self.AVF_]['avf_INTERVAL_3_MAX'] Time_P_AVF=self.avf_INTERVAL_3.query("AVF == '{0}'".format(P_AVF)) int_time_P_AVF= float(Time_P_AVF["x"].values[0]) #Valores AVR AVR_max= df[self.AVR_].min() Time_AVR=df.query("AVR == '{0}'".format(AVR_max)) int_timeAVR= float(Time_AVR["x"].values[0]) ST_AVR= values_ST_T[self.AVR_]['avr_INTERVAL_1_MAX'] Time_ST_AVR=self.avr_INTERVAL_1.query("AVR == '{0}'".format(ST_AVR)) int_time_ST_AVR= float(Time_ST_AVR["x"].values[0]) T_AVR= values_ST_T[self.AVR_]['avr_INTERVAL_2_MAX'] Time_T_AVR=self.avr_INTERVAL_2.query("AVR == '{0}'".format(T_AVR)) int_time_T_AVR= float(Time_T_AVR["x"].values[0]) P_AVR= values_ST_T[self.AVR_]['avr_INTERVAL_3_MAX'] Time_P_AVR=self.avr_INTERVAL_3.query("AVR == '{0}'".format(P_AVR)) int_time_P_AVR= float(Time_P_AVR["x"].values[0]) #Valores AVL AVL_max= df[self.AVL_].max() Time_AVL=df.query("AVL == '{0}'".format(AVL_max)) int_timeAVL= float(Time_AVL["x"].values[0]) ST_AVL= values_ST_T[self.AVL_]['avl_INTERVAL_1_MAX'] Time_ST_AVL=self.avl_INTERVAL_1.query("AVL == '{0}'".format(ST_AVL)) int_time_ST_AVL= float(Time_ST_AVL["x"].values[0]) T_AVL= values_ST_T[self.AVL_]['avl_INTERVAL_2_MAX'] Time_T_AVL=self.avl_INTERVAL_2.query("AVL == '{0}'".format(T_AVL)) int_time_T_AVL= float(Time_T_AVL["x"].values[0]) P_AVL= values_ST_T[self.AVL_]['avl_INTERVAL_3_MAX'] Time_P_AVL=self.avl_INTERVAL_3.query("AVL == '{0}'".format(P_AVL)) int_time_P_AVL= float(Time_P_AVL["x"].values[0]) # ################################### # Content try: base_path= sys._MEIPASS except Exception: base_path=os.path.abspath(".") path5 = os.path.join(base_path, 'Report.pdf') fileName = path5 documentTitle = 'ECG REPORT' title = 'ECG REPORT' subTitle = 'Name:'+persona["Nombre"] +" Age:"+persona["Edad"] +" Gender:"+persona["Genero"] textLines = [ 'D1 / R:'+str(float(D1_max))+' ST: '+str(float(ST_D1))+' T: '+str(float(T_D1))+' P: '+str(float(P_D1)), 'Time: '+str(float(int_timeD1)) +' Time: '+str(float(int_time_ST_D1))+' Time: '+str(float(int_time_T_D1))+' Time: '+str(float(int_time_P_D1)), 'D2 / R:'+str(float(D2_max))+' ST: '+str(float(ST_D2))+' T: '+str(float(T_D2)) +' P: '+str(float(P_D2)), 'Time: '+str(float(int_timeD2)) +' Time: '+str(float(int_time_ST_D2))+' Time: '+str(float(int_time_T_D2))+' Time: '+str(float(int_time_P_D2)), 'D3 / R:'+str(float(D3_max))+' ST: '+str(float(ST_D3))+' T: '+str(float(T_D3))+' P: '+str(float(P_D3)), 'Time: '+str(float(int_timeD3)) +' Time: '+str(float(int_time_ST_D3))+' Time: '+str(float(int_time_T_D3))+' Time: '+str(float(int_time_P_D3)), 'aVF / R:'+str(float(AVF_max)) +' ST: '+str(float(ST_AVF))+' T: '+str(float(T_AVF))+' P: '+str(float(P_AVF)), 'Time: '+str(float(int_timeAVF)) +' Time: '+str(float(int_time_ST_AVF))+' Time: '+str(float(int_time_T_AVF))+' Time: '+str(float(int_time_P_AVF)), 'aVR / R:'+str(float(AVR_max)) +' ST: '+str(float(ST_AVR))+' T: '+str(float(T_AVR))+' P: '+str(float(P_AVR)), 'Time: '+str(float(int_timeAVR)) +' Time: '+str(float(int_time_ST_AVR))+' Time: '+str(float(int_time_T_AVR))+' Time: '+str(float(int_time_P_AVR)), 'aVL / R:'+str(float(AVL_max)) +' ST: '+str(float(T_AVL))+' T: '+str(float(ST_AVL))+' P: '+str(float(P_AVL)), 'Time: '+str(float(int_timeAVL)) +' Time: '+str(float(int_time_ST_AVL))+' Time: '+str(float(int_time_T_AVL))+' Time: '+str(float(int_time_P_AVL)), ] # ################################### # 0) Create document from reportlab.pdfgen import canvas pdf = canvas.Canvas(fileName) pdf.setTitle(documentTitle) #self.drawMyRuler#(pdf) # ################################### # 1) Title :: Set fonts # # Print available fonts # for font in pdf.getAvailableFonts(): # print(font) # Register a new font from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase import pdfmetrics try: base_path= sys._MEIPASS except Exception: base_path=os.path.abspath(".") path4 = os.path.join(base_path, 'SakBunderan.ttf') print(path4) pdfmetrics.registerFont( TTFont('abc', path4) ) pdf.setFont('abc', 36) pdf.drawCentredString(300, 770, title) # ################################### # 2) Sub Title # RGB - Red Green and Blue pdf.setFillColorRGB(0, 0, 255) pdf.setFont("Courier-Bold", 24) pdf.drawCentredString(290,720, subTitle) # ################################### # 3) Draw a line pdf.line(30, 710, 550, 710) # ################################### # 4) Text object :: for large amounts of text from reportlab.lib import colors text = pdf.beginText(40, 680) text.setFont("Courier", 13) text.setFillColor(colors.red) val=True for line in textLines: text.textLine(line) if val: text.setFillColor(colors.black) val=False else : text.setFillColor(colors.red) val=True text.textLine("") #Valor maximo de X value_max_X=float(df["x"].max())/3600 text.textLine("") text.textLine("") text.textLine("") text.textLine("") text.setFillColor(colors.blue) truncate = "%.6f" % value_max_X text.textLine('Connetion time: '+str(truncate) +" h") text.textLine("") text.textLine('Heart rate: '+str(round(contPuls)*10) +" bpm") pdf.drawText(text) pdf.save()