Exemple #1
0
    def set_wlet_pars(self):

        # period validator
        vali = self.periodV

        # read all the LineEdits:

        text = self.T_min.text()
        T_min = text.replace(",", ".")
        check, _, _ = vali.validate(T_min, 0)
        if self.debug:
            print("Min periodValidator output:", check, "value:", T_min)
        if check == 0:
            self.OutOfBounds = MessageWindow("Wavelet periods out of bounds!",
                                             "Value Error")
            return False
        self.T_min_value = float(T_min)

        step_num = self.step_num.text()
        check, _, _ = posintV.validate(step_num, 0)
        if self.debug:
            print("# Periods posintValidator:", check, "value:", step_num)
        if check == 0:
            self.OutOfBounds = MessageWindow(
                "The Number of periods must be a positive integer!",
                "Value Error")
            return False
        self.step_num_value = int(step_num)

        text = self.T_max.text()

        T_max = text.replace(",", ".")
        check, _, _ = vali.validate(T_max, 0)
        if self.debug:
            print("Max periodValidator output:", check)
            print(f"Max period value: {self.T_max.text()}")
        if check == 0 or check == 1:
            self.OutOfBounds = MessageWindow(
                "Wavelet highest period out of bounds!", "Value Error")
            return False
        self.T_max_value = float(T_max)

        text = self.p_max.text()
        p_max = text.replace(",", ".")
        check, _, _ = posfloatV.validate(p_max, 0)  # checks for positive float
        if check == 0:
            self.OutOfBounds = MessageWindow("Powers are positive!",
                                             "Value Error")
            return False

        # check for empty string:
        if p_max:
            self.p_max_value = float(p_max)
        else:
            self.p_max_value = None

        # success!
        return True
Exemple #2
0
    def calc_envelope(self):

        L = self.get_L(self.L_edit)
        if not L:
            return
        if self.debug:
            print("Calculating envelope with L = ", L)
            
        if L/self.dt < 3:
            self.OutOfBounds = MessageWindow(
                f"Minimum sliding\nwindow size is {3*self.dt}{self.time_unit} !",
                "Value Error",
            )
            L = None
            return

        if L / self.dt > self.df.shape[0]:
            maxL = self.df.shape[0] * self.dt
            self.OutOfBounds = MessageWindow(
                f"Maximum sliding window\nsize is {maxL:.2f} {self.time_unit}!",
                "Value Error",
            )
            L = None
            return

        # cut of frequency set?!
        if self.cb_trend.isChecked():

            trend = self.calc_trend()
            if trend is None:
                return
            
            signal = self.raw_signal - trend
            envelope = pyboat.sliding_window_amplitude(signal,
                                                       window_size = L,
                                                       dt = self.dt)

            if self.cb_detrend.isChecked():
                return envelope

            # fits on the original signal!
            else:
                return envelope + trend

        # otherwise add the mean
        else:
            if self.debug:
                print("calculating envelope for raw signal", L)

            mean = self.raw_signal.mean()
            envelope = pyboat.sliding_window_amplitude(
                self.raw_signal, window_size = L, dt = self.dt
            )
            return envelope + mean
Exemple #3
0
    def run_fourier_ana(self):
        if not np.any(self.raw_signal):
            self.NoSignalSelected = MessageWindow(
                "Please select a signal first!", "No Signal")
            return False

        # shift new analyser windows
        self.w_position += 20

        if self.cb_use_detrended2.isChecked():
            trend = self.calc_trend()
            signal = self.raw_signal - trend
        else:
            signal = self.raw_signal

        if self.cb_use_envelope2.isChecked():
            L = self.get_L(self.L_edit)
            signal = pyboat.normalize_with_envelope(signal, L, self.dt)

        # periods or frequencies?
        if self.cb_FourierT.isChecked():
            show_T = False
        else:
            show_T = True

        self.anaWindows[self.w_position] = FourierAnalyzer(
            signal=signal,
            dt=self.dt,
            signal_id=self.signal_id,
            position=self.w_position,
            time_unit=self.time_unit,
            show_T=show_T,
        )
Exemple #4
0
    def get_T_c(self, T_c_edit):

        '''
        Uses self.T_c_edit, argument just for clarity. Checks
        for empty input, this function only gets called when
        a detrending operation is requested. Hence, an empty
        QLineEdit will display a user warning and return nothing..
        '''

        # value checking done by validator, accepts also comma '1,1' !
        tc = T_c_edit.text().replace(",", ".")        
        try:
            T_c = float(tc)
            if self.debug:
                print("T_c set to:", T_c)
            return T_c
        
        # empty line edit
        except ValueError:
            self.NoTrend = MessageWindow(
                "Detrending parameter not set,\n" + "specify a cut-off period!",
                "No Trend",
            )
            
            if self.debug:
                print("T_c ValueError", tc)
            return None
Exemple #5
0
    def do_annealRidge_detection(self, anneal_pars):
        """ Gets called from the AnnealConfigWindow 
        deactivated for the public version..!
        """

        if anneal_pars is None:
            self.noValues = MessageWindow(
                "No parameters set for\nsimulated annealing!", "No Parameters")
            return

        # todo add out-of-bounds parameter check in config window
        ini_per = anneal_pars["ini_per"]
        ini_T = anneal_pars["ini_T"]
        Nsteps = int(anneal_pars["Nsteps"])
        max_jump = int(anneal_pars["max_jump"])
        curve_pen = anneal_pars["curve_pen"]

        # get modulus index of initial straight line ridge
        y0 = np.where(self.periods < ini_per)[0][-1]

        ridge_y, cost = core.find_ridge_anneal(self.modulus,
                                               y0,
                                               ini_T,
                                               Nsteps,
                                               mx_jump=max_jump,
                                               curve_pen=curve_pen)

        self.ridge = ridge_y

        # draw the ridge and make ridge_data
        self._has_ridge = True
        self.draw_ridge()
Exemple #6
0
    def draw_ridge(self):
        """ makes also the ridge_data !! """

        if not self._has_ridge:
            self.e = MessageWindow("Run a ridge detection first!", "No Ridge")
            return

        ridge_data = core.eval_ridge(
            self.ridge,
            self.wlet,
            self.signal,
            self.periods,
            self.tvec,
            power_thresh=self.power_thresh,
            smoothing_wsize=self.rsmoothing,
        )

        # plot the ridge
        ax_spec = self.wCanvas.fig.axes[1]  # the spectrum

        # already has a plotted ridge
        if ax_spec.lines:
            ax_spec.lines = []  # remove old ridge line
            self.cb_coi.setCheckState(0)  # remove COI

        pl.draw_Wavelet_ridge(ax_spec, ridge_data, marker_size=1.5)

        # refresh the canvas
        self.wCanvas.draw()

        self.ridge_data = ridge_data
Exemple #7
0
    def calc_envelope(self):

        if self.L < 3:
            self.OutOfBounds = MessageWindow(
                f"Minimum sliding\nwindow size is {3*self.dt}{self.time_unit} !",
                "Value Error",
            )
            self.L = None
            return

        if self.L > self.Nt:
            maxL = self.Nt * self.dt
            self.OutOfBounds = MessageWindow(
                f"Maximum sliding window\nsize is {maxL:.2f} {self.time_unit}!",
                "Value Error",
            )
            self.L = None
            return

        # cut of frequency set?!
        if self.T_c:
            if self.debug:
                print("calculating envelope for detrended signal", self.L,
                      self.T_c)

            trend = self.calc_trend()
            signal = self.raw_signal - trend
            envelope = pyboat.sliding_window_amplitude(signal,
                                                       window_size=self.L)

            if self.cb_detrend.isChecked():
                return envelope

            # fits on the original signal!
            else:
                return envelope + trend

        # otherwise add the mean
        else:
            if self.debug:
                print("calculating envelope for raw signal", self.L)

            mean = self.raw_signal.mean()
            envelope = pyboat.sliding_window_amplitude(self.raw_signal,
                                                       window_size=self.L)
            return envelope + mean
Exemple #8
0
    def run_fourier_ana(self):
        if not np.any(self.raw_signal):
            self.NoSignalSelected = MessageWindow(
                "Please select a signal first!", "No Signal")
            return False

        # shift new analyser windows
        self.w_position += 20

        if self.cb_use_detrended2.isChecked() and not self.T_c:
            self.NoTrend = MessageWindow(
                "Detrending not set, can not use detrended signal!",
                "No Trend")
            return

        elif self.cb_use_detrended2.isChecked():
            trend = self.calc_trend()
            signal = self.raw_signal - trend
        else:
            signal = self.raw_signal

        if self.cb_use_envelope2.isChecked() and not self.L:
            self.NoTrend = MessageWindow(
                "Envelope parameter not set,\n" +
                "specify a sliding window size!",
                "No Envelope",
            )
            return

        elif self.cb_use_envelope2.isChecked():
            signal = pyboat.normalize_with_envelope(signal, self.L)

        # periods or frequencies?
        if self.cb_FourierT.isChecked():
            show_T = False
        else:
            show_T = True

        self.anaWindows[self.w_position] = FourierAnalyzer(
            signal=signal,
            dt=self.dt,
            signal_id="Synthetic Signal",
            position=self.w_position,
            time_unit=self.time_unit,
            show_T=show_T,
        )
Exemple #9
0
    def toggle_envelope(self, state):
        if state == Qt.Checked:

            # user warning - no effect without L set
            if not self.L:
                self.NoEnvelope = MessageWindow(
                    "Specify a sliding window size!", "Missing value")

        # signal selected?

        if self.raw_signal is not None:
            self.doPlot()
Exemple #10
0
    def do_maxRidge_detection(self):

        ridge_y = core.get_maxRidge_ys(self.modulus)
        self.ridge = ridge_y

        if not np.any(ridge_y):
            self.e = MessageWindow("No ridge found..check spectrum!",
                                   "Ridge detection error")
            return

        self._has_ridge = True
        self.draw_ridge()  # ridge_data made here
Exemple #11
0
    def vector_prep(self, signal_id):
        """ 
        prepares raw signal vector (NaN removal) and
        corresponding time vector 
        """
        if self.debug:
            print("preparing", signal_id)

        # checks for empty signal_id string
        if signal_id:
            raw_signal = self.df[signal_id]

            NaNswitches = np.sum(np.diff(np.isnan(raw_signal)))
            if NaNswitches > 1:
                print(
                    f'Warning, non-contiguous NaN region found in {signal_id}!'
                )

                self.NonContiguous = MessageWindow(
                    '''
                Non contiguous regions of missing values 
                encountered, using linear interpolation. 

                Try 'Import..' from the main menu 
                to interpolate missing values in all signals!
                ''', "Missing Values")
                self.raw_signal = pyboat.core.interpolate_NaNs(raw_signal)
            else:
                # remove contiguous (like trailing) NaN region
                self.raw_signal = raw_signal[~np.isnan(raw_signal)]

            self.tvec = np.arange(0, len(self.raw_signal), step=1) * self.dt
            return True  # success

        else:
            self.NoSignalSelected = MessageWindow("Please select a signal!",
                                                  "No Signal")
            return False
Exemple #12
0
    def get_OutPath(self):
        '''
        Reads the self.OutPath_edit 
        There is no validator but an os.path
        check is done!
        '''

        path = self.OutPath_edit.text()

        if not os.path.isdir(path):
            self.e = MessageWindow("Specified path is not a valid directory..",
                                   "Invalid export path")
            return None
        return path
Exemple #13
0
    def toggle_trend(self, state):

        if self.debug:
            print("old state:", self.cb_trend.isChecked())

        if state == Qt.Checked:
            # user warning - no effect without T_c set
            if not self.T_c:
                self.NoTrend = MessageWindow("Specify a cut-off period!",
                                             "Missing value")

        # signal selected?

        if self.raw_signal is not None:
            self.doPlot()
Exemple #14
0
    def Load_and_init_Viewer(self):

        if self.debug:
            print("function Viewer_Ini called")

        # load a table directly
        df, err_msg = load_data(self.debug)

        if err_msg:
            self.error = MessageWindow(err_msg, "Loading error")
            return

        self.nViewers += 1

        # initialize new DataViewer with the loaded data
        self.DataViewers[self.nViewers] = DataViewer(data=df, debug=self.debug)
Exemple #15
0
    def ini_plot_readout(self):

        if not self._has_ridge:
            self.e = MessageWindow('Do a ridge detection first!', 'No Ridge')
            return

        # to keep the line shorter..
        wo = self.w_offset
        self.ResultWindows[wo] = WaveletReadoutWindow(
            self.signal_id,
            self.ridge_data,
            time_unit=self.time_unit,
            draw_coi=self.cb_coi.isChecked(),
            pos_offset=self.w_offset,
            DEBUG=self.DEBUG)
        self.w_offset += 20
Exemple #16
0
    def run_wavelet_ana(self):
        """ run the Wavelet Analysis """

        if not np.any(self.raw_signal):
            self.NoSignalSelected = MessageWindow(
                "Please select a signal first!", "No Signal"
            )
            return False

        wlet_pars = self.set_wlet_pars()  # Error handling done there
        if not wlet_pars:
            if self.debug:
                print("Wavelet parameters could not be set!")
            return False

        if self.cb_use_detrended.isChecked():
            trend = self.calc_trend()
            signal = self.raw_signal - trend
        else:
            signal = self.raw_signal


        if self.cb_use_envelope.isChecked():
            L = self.get_L(self.L_edit)
            signal = pyboat.normalize_with_envelope(signal, L, dt = self.dt)

        self.w_position += 20

        
        self.anaWindows[self.w_position] = WaveletAnalyzer(
            signal=signal,
            dt=self.dt,
            T_min = wlet_pars['T_min'],
            T_max = wlet_pars['T_max'],
            p_max = wlet_pars['p_max'],
            step_num=wlet_pars['step_num'],
            position=self.w_position,
            signal_id=self.signal_id,
            time_unit=self.time_unit,            
            DEBUG=self.debug,
        )
Exemple #17
0
    def get_L(self, L_edit):

        # value checking done by validator, accepts also comma '1,1' !
        L = L_edit.text().replace(",", ".")
        try:
            L = int(L)

        # empty line edit
        except ValueError:
            self.NoTrend = MessageWindow(
                "Envelope parameter not set,\n" + "specify a sliding window size!",
                "No Envelope",
            )
            
            if self.debug:
                print("L ValueError", L)
            return None
        
        if self.debug:
            print("L set to:", L)
        return L
Exemple #18
0
    def vector_prep(self, signal_id):
        """ 
        prepares raw signal vector (NaN removal) and
        corresponding time vector 
        """
        if self.debug:
            print("preparing", signal_id)

        # checks for empty signal_id string
        if signal_id:
            self.raw_signal = self.df[signal_id]

            # remove NaNs
            self.raw_signal = self.raw_signal[~np.isnan(self.raw_signal)]
            self.tvec = np.arange(0, len(self.raw_signal), step=1) * self.dt
            return True  # success

        else:
            self.NoSignalSelected = MessageWindow(
                "Please select a signal!", "No Signal"
            )
            return False
Exemple #19
0
    def run_batch(self):
        """
        Takes the ui wavelet settings and 
        spwans the batch processing Widget
        """

        # reads the wavelet analysis settings from the ui input
        wlet_pars = self.set_wlet_pars()  # Error handling done there
        if not wlet_pars:
            return

        if self.debug:
            print(f'Started batch processing with {wlet_pars}')

        # Spawning the batch processing config widget
        # is bound to parent Wavelet Window
        self.bc = BatchProcessWindow(self, self.debug)
        self.bc.initUI(wlet_pars)

        return
        print("batch processing done!")
        msg = f"Processed {Nproc} signals!\n ..saved results to {dir_name}"
        self.msg = MessageWindow(msg, "Finished")
Exemple #20
0
    def save_out_trend(self):

        if not np.any(self.raw_signal):
            self.NoSignalSelected = MessageWindow(
                "Please select a signal first!", "No Signal"
            )
            return

        if self.debug:
            print("saving trend out")

        # -------calculate trend and detrended signal------------
        trend = self.calc_trend()
        dsignal = self.raw_signal - trend

        # add everything to a pandas data frame
        data = np.array([self.raw_signal, trend, dsignal]).T  # stupid pandas..
        columns = ["raw", "trend", "detrended"]
        df_out = pd.DataFrame(data=data, columns=columns)
        # ------------------------------------------------------

        if self.debug:
            print("df_out", df_out[:10])
            print("trend", trend[:10])
        dialog = QFileDialog()
        options = QFileDialog.Options()

        # ----------------------------------------------------------
        default_name = "trend_" + str(self.signal_id)
        format_filter = "Text File (*.txt);; CSV ( *.csv);; Excel (*.xlsx)"
        # -----------------------------------------------------------
        file_name, sel_filter = dialog.getSaveFileName(
            self, "Save as", default_name, format_filter, None, options=options
        )

        # dialog cancelled
        if not file_name:
            return

        file_ext = file_name.split(".")[-1]

        if self.debug:
            print("selected filter:", sel_filter)
            print("out-path:", file_name)
            print("extracted extension:", file_ext)

        if file_ext not in ["txt", "csv", "xlsx"]:
            self.e = MessageWindow(
                "Ouput format not supported..\n"
                + "Please append .txt, .csv or .xlsx\n"
                + "to the file name!",
                "Unknown format",
            )
            return

        # ------the write out calls to pandas----------------

        float_format = "%.2f"  # still old style :/

        if file_ext == "txt":
            df_out.to_csv(file_name, index=False, sep="\t", float_format=float_format)

        elif file_ext == "csv":
            df_out.to_csv(file_name, index=False, sep=",", float_format=float_format)

        elif file_ext == "xlsx":
            df_out.to_excel(file_name, index=False, float_format=float_format)

        else:
            if self.debug:
                print("Something went wrong during save out..")
            return
        if self.debug:
            print("Saved!")
Exemple #21
0
    def save_out(self):

        dialog = QFileDialog()
        options = QFileDialog.Options()

        # ----------------------------------------------------------
        base_name = str(self.signal_id).replace(' ', '-')
        default_name = os.path.join(os.path.expanduser('~'),
                                    base_name + '_ridgeRO')
        format_filter = "Text File (*.txt);; csv ( *.csv);; MS Excel (*.xlsx)"
        # -----------------------------------------------------------
        file_name, sel_filter = dialog.getSaveFileName(self,
                                                       "Save ridge readout as",
                                                       default_name,
                                                       format_filter,
                                                       "(*.txt)",
                                                       options=options)

        # dialog cancelled
        if not file_name:
            return

        file_ext = file_name.split(".")[-1]

        if self.DEBUG:
            print("selected filter:", sel_filter)
            print("out-path:", file_name)
            print("extracted extension:", file_ext)
            print("ridge data keys:", self.ridge_data.keys())

        if file_ext not in ["txt", "csv", "xlsx"]:
            self.e = MessageWindow(
                "Ouput format not supported..\n" +
                "Please append .txt, .csv or .xlsx\n" + "to the file name!",
                "Unknown format",
            )
            return

        # the write out calls
        float_format = "%.2f"  # still old style :/

        if file_ext == "txt":
            self.ridge_data.to_csv(file_name,
                                   index=False,
                                   sep="\t",
                                   float_format=float_format)

        elif file_ext == "csv":
            self.ridge_data.to_csv(file_name,
                                   index=False,
                                   sep=",",
                                   float_format=float_format)

        elif file_ext == "xlsx":
            self.ridge_data.to_excel(file_name,
                                     index=False,
                                     float_format=float_format)

        else:
            if self.DEBUG:
                print("Something went wrong during save out..")
            return
        if self.DEBUG:
            print("Saved!")
Exemple #22
0
    def set_wlet_pars(self):

        '''
        Retrieves and checks the set wavelet parameters
        of the 'Analysis' input box reading the following
        QLineEdits:

        self.Tmin
        self.Tmax
        self.step_num
        self.pmax

        Further the checkboxes regarding detrending and amplitude
        normalization are evaluated. And

        self.get_L()
        self.get_T_c()

        are called if needed. These respective parameters are set to False
        if the opereation in question is not requested.

        Returns
        -------

        wlet_pars : dictionary holding the retrieved parameters,
                    L and T_c are set to None if no amplitude
                    normalization or detrending operation should be done

        '''

        wlet_pars = {}

        # period validator
        vali = self.periodV

        # -- read all the QLineEdits --

        text = self.T_min.text()
        T_min = text.replace(",", ".")
        check, _, _ = vali.validate(T_min, 0)
        if self.debug:
            print("Min periodValidator output:", check, "value:", T_min)
        if check == 0:
            self.OutOfBounds = MessageWindow(
                "Wavelet periods out of bounds!", "Value Error"
            )
            return False

        wlet_pars['T_min'] = float(T_min)
                
        step_num = self.step_num.text()
        check, _, _ = posintV.validate(step_num, 0)
        if self.debug:
            print("# Periods posintValidator:", check, "value:", step_num)
        if check == 0:
            self.OutOfBounds = MessageWindow(
                "The Number of periods must be a positive integer!", "Value Error"
            )
            return False

        wlet_pars['step_num'] = int(step_num)
        if int(step_num) > 1000:

            choice = QMessageBox.question(
                self,
                "Too much periods?: ",
                "High number of periods: Do you want to continue?",
                QMessageBox.Yes | QMessageBox.No,
            )
            if choice == QMessageBox.Yes:
                pass
            else:
                return False        
        
        text = self.T_max.text()
        T_max = text.replace(",", ".")
        check, _, _ = vali.validate(T_max, 0)
        if self.debug:
            print("Max periodValidator output:", check)
            print(f"Max period value: {self.T_max.text()}")
        if check == 0 or check == 1:
            self.OutOfBounds = MessageWindow(
                "Wavelet highest period out of bounds!", "Value Error"
            )
            return False
        wlet_pars['T_max'] = float(T_max)

        text = self.p_max.text()
        p_max = text.replace(",", ".")
        check, _, _ = posfloatV.validate(p_max, 0)  # checks for positive float
        if check == 0:
            self.OutOfBounds = MessageWindow("Powers are positive!", "Value Error")
            return False

        # check for empty string:
        if p_max:
            wlet_pars['p_max'] = float(p_max)
        else:
            wlet_pars['p_max'] = None

        # -- the checkboxes --
            
        # detrend for the analysis?
        if self.cb_use_detrended.isChecked():
            T_c = self.get_T_c(self.T_c_edit)
            if T_c is None:
                return False # abort settings            
            wlet_pars['T_c'] = T_c
        else:
            # indicates no detrending requested
            wlet_pars['T_c'] = False
            
        # amplitude normalization is downstram of detrending!
        if self.cb_use_envelope.isChecked():
            L = self.get_L(self.L_edit)        
            if L is None:
                return False # abort settings                        
            wlet_pars['L'] = L
        else:
            # indicates no ampl. normalization
            wlet_pars['L'] = False
                    
        # success!
        return wlet_pars
Exemple #23
0
    def run_batch(self):
        '''
        Retrieve all batch settings and loop over the signals
        present in the parentDV

        '''

        dataset_name = self.parentDV.df.name

        if self.export_options.isChecked():
            OutPath = self.get_OutPath()
            if OutPath is None:
                return

        # TODO: parallelize
        ridge_results, df_fouriers = self.do_the_loop()

        # check for empty ridge_results
        if not ridge_results:
            self.NoResults = MessageWindow(
                'All ridges below threshold.. no results!', 'No results')
            return

        # --- compute the time-averaged powers ---

        if self.cb_power_dis.isChecked() or self.cb_sorted_powers.isChecked():

            powers_series = em.average_power_distribution(
                ridge_results.values(), ridge_results.keys(), exclude_coi=True)

        if self.cb_power_dis.isChecked():
            # plot the distribution
            self.pdw = PowerDistributionWindow(powers_series,
                                               dataset_name=dataset_name)

        # save out the sorted average powers
        if self.export_options.isChecked() and self.cb_sorted_powers.isChecked(
        ):
            fname = os.path.join(OutPath, f'{dataset_name}_ridge-powers.csv')
            powers_series.to_csv(fname, sep=',', index=True, header=False)

        # --- compute summary statistics over time ---

        if self.cb_plot_ens_dynamics.isChecked(
        ) or self.cb_save_ensemble_dynamics.isChecked():
            # res is a tuple of  DataFrames, one each for
            # periods, amplitude, power and phase
            res = em.get_ensemble_dynamics(ridge_results.values())

        if self.cb_plot_ens_dynamics.isChecked():
            self.edw = EnsembleDynamicsWindow(
                res,
                dt=self.parentDV.dt,
                time_unit=self.parentDV.time_unit,
                dataset_name=dataset_name)

        if self.export_options.isChecked(
        ) and self.cb_save_ensemble_dynamics.isChecked():
            # create time axis, all DataFrames have same number of rows
            tvec = np.arange(res[0].shape[0]) * self.parentDV.dt
            for obs, df in zip(['periods', 'amplitudes', 'powers', 'phasesR'],
                               res):
                fname = os.path.join(OutPath, f'{dataset_name}_{obs}.csv')
                df.index = tvec
                df.index.name = 'time'
                df.to_csv(fname, sep=',', float_format='%.3f')

        # --- Fourier Distribution Outputs ---

        if self.cb_plot_Fourier_dis.isChecked():

            self.fdw = FourierDistributionWindow(df_fouriers,
                                                 self.parentDV.time_unit,
                                                 dataset_name)

        if self.export_options.isChecked(
        ) and self.cb_save_Fourier_dis.isChecked():

            fname = os.path.join(OutPath,
                                 f'{dataset_name}_fourier-distribution.csv')

            # save out median and quartiles of Fourier powers
            df_fdis = pd.DataFrame(index=df_fouriers.index)
            df_fdis['Median'] = df_fouriers.median(axis=1)
            df_fdis['Q1'] = df_fouriers.quantile(q=0.25, axis=1)
            df_fdis['Q3'] = df_fouriers.quantile(q=0.75, axis=1)

            df_fdis.to_csv(fname, sep=',', float_format='%.3f')

        if self.debug:
            print(list(ridge_results.items())[:2])
Exemple #24
0
    def run_wavelet_ana(self):
        """ run the Wavelet Analysis """

        if not np.any(self.raw_signal):
            self.NoSignalSelected = MessageWindow(
                "Please select a signal first!", "No Signal")
            return False

        succ = self.set_wlet_pars()  # Error handling done there
        if not succ:
            if self.debug:
                print("Wavelet parameters could not be set!")
            return False

        # move to set_wlet_pars?!
        if self.step_num_value > 1000:

            choice = QMessageBox.question(
                self,
                "Too much periods?: ",
                "High number of periods: Do you want to continue?",
                QMessageBox.Yes | QMessageBox.No,
            )
            if choice == QMessageBox.Yes:
                pass
            else:
                return

        # detrend for the analysis?
        if self.cb_use_detrended.isChecked() and not self.T_c:
            self.NoTrend = MessageWindow(
                "Detrending parameter not set,\n" +
                "specify a cut-off period!",
                "No Trend",
            )
            return

        elif self.cb_use_detrended.isChecked():
            trend = self.calc_trend()
            signal = self.raw_signal - trend
        else:
            signal = self.raw_signal

        # amplitude normalization is downstram of detrending!
        if self.cb_use_envelope.isChecked() and not self.L:
            self.NoTrend = MessageWindow(
                "Envelope parameter not set,\n" +
                "specify a sliding window size!",
                "No Envelope",
            )
            return

        elif self.cb_use_envelope.isChecked():
            signal = pyboat.normalize_with_envelope(signal, self.L)

        self.w_position += 20

        self.anaWindows[self.w_position] = WaveletAnalyzer(
            signal=signal,
            dt=self.dt,
            T_min=self.T_min_value,
            T_max=self.T_max_value,
            position=self.w_position,
            signal_id="Synthetic Signal",
            step_num=self.step_num_value,
            p_max=self.p_max_value,
            time_unit=self.time_unit,
            DEBUG=self.debug,
        )
Exemple #25
0
    def doPlot(self):

        if self.raw_signal is None:
            self.NoSignal = MessageWindow("Please create a signal first!",
                                          "No Signal")

        if self.debug:
            print(
                "called Plotting [raw] [trend] [detrended] [envelope]",
                self.cb_raw.isChecked(),
                self.cb_trend.isChecked(),
                self.cb_detrend.isChecked(),
                self.cb_envelope.isChecked(),
            )

        # check if trend is needed
        if self.T_c and (self.cb_trend.isChecked()
                         or self.cb_detrend.isChecked()):
            if self.debug:
                print("Calculating trend with T_c = ", self.T_c)
            trend = self.calc_trend()

        else:
            trend = None

        # envelope calculation
        if self.L and self.cb_envelope.isChecked():
            if self.debug:
                print("Calculating envelope with L = ", self.L)
            envelope = self.calc_envelope()

        else:
            envelope = None

        self.tsCanvas.fig1.clf()

        ax1 = pl.mk_signal_ax(self.time_unit, fig=self.tsCanvas.fig1)
        self.tsCanvas.fig1.add_axes(ax1)

        if self.debug:
            print(
                f"plotting signal and trend with {self.tvec[:10]}, {self.raw_signal[:10]}"
            )

        if self.cb_raw.isChecked():
            pl.draw_signal(ax1, time_vector=self.tvec, signal=self.raw_signal)

        if trend is not None and self.cb_trend.isChecked():
            pl.draw_trend(ax1, time_vector=self.tvec, trend=trend)

        if trend is not None and self.cb_detrend.isChecked():
            ax2 = pl.draw_detrended(ax1,
                                    time_vector=self.tvec,
                                    detrended=self.raw_signal - trend)
            ax2.legend(fontsize=pl.tick_label_size)
        if envelope is not None and not self.cb_detrend.isChecked():
            pl.draw_envelope(ax1, time_vector=self.tvec, envelope=envelope)

        # plot on detrended axis
        if envelope is not None and self.cb_detrend.isChecked():
            pl.draw_envelope(ax2, time_vector=self.tvec, envelope=envelope)
            ax2.legend(fontsize=pl.tick_label_size)
        self.tsCanvas.fig1.subplots_adjust(bottom=0.15, left=0.15, right=0.85)
        # add a simple legend
        ax1.legend(fontsize=pl.tick_label_size)

        self.tsCanvas.draw()
        self.tsCanvas.show()
Exemple #26
0
    def create_signal(self):
        """
        Retrieves all paramters from the synthesizer controls
        and calls the ssg. All line edits have validators set,
        however we have to check for intermediate empty inputs..
        """

        # the signal components
        components = []
        weights = []

        # number of sample points
        if not self.Nt_edit.hasAcceptableInput():
            self.OutOfBounds = MessageWindow(
                "Minimum number of sample points is 10!", "Value Error")
            return

        self.Nt = int(self.Nt_edit.text())
        if self.debug:
            print("Nt changed to:", self.Nt)

        self.set_initial_periods(force=True)
        self.set_initial_T_c(force=True)

        T_edits = [self.T11_edit, self.T12_edit, self.T21_edit, self.T22_edit]

        # check for valid inputs
        for T_e in T_edits:

            if self.debug:
                print(f"Is enabled: {T_e.isEnabled()}")
                print(f"Checking T_edits: {T_e.text()}")
                print(f"Validator output: {T_e.hasAcceptableInput()}")

            if not T_e.isEnabled():
                continue

            if not T_e.hasAcceptableInput():
                self.OutOfBounds = MessageWindow(
                    "All periods must be greater than 0!", "Value Error")
                return

        # envelope before chirp creation
        if self.env_box.isChecked():

            if not self.tau_edit.hasAcceptableInput():
                self.OutOfBounds = MessageWindow("Missing envelope parameter!",
                                                 "Value Error")
                return

            tau = float(self.tau_edit.text()) / self.dt
            env = ssg.create_exp_envelope(tau, self.Nt)
            if self.debug:
                print(f"Creating the envelope with tau = {tau}")

        else:
            env = 1  # no envelope

        if self.chirp1_box.isChecked():

            if not self.A1_edit.hasAcceptableInput():
                self.OutOfBounds = MessageWindow(
                    "Set an amplitude for oscillator1!", "Value Error")
                return

            # the periods
            T11 = float(self.T11_edit.text()) / self.dt
            T12 = float(self.T12_edit.text()) / self.dt
            A1 = float(self.A1_edit.text())
            chirp1 = ssg.create_chirp(T11, T12, self.Nt)
            components.append(env * chirp1)
            weights.append(A1)

        if self.chirp2_box.isChecked():

            if not self.A2_edit.hasAcceptableInput():
                self.OutOfBounds = MessageWindow(
                    "Set an amplitude for oscillator2!", "Value Error")
                return

            T21 = float(self.T21_edit.text()) / self.dt
            T22 = float(self.T22_edit.text()) / self.dt
            A2 = float(self.A2_edit.text())
            chirp2 = ssg.create_chirp(T21, T22, self.Nt)
            components.append(env * chirp2)
            weights.append(A2)

        # noise
        if self.noise_box.isChecked():
            # QDoubleValidator is a screw up..
            alpha = float(self.alpha_edit.text())
            if not 0 < alpha < 1:
                self.OutOfBounds = MessageWindow(
                    "AR1 parameter must be smaller than 1!", "Value Error")
                return
            if not self.d_edit.hasAcceptableInput():
                self.OutOfBounds = MessageWindow("Missing noise parameters!",
                                                 "Value Error")
                return

            d = float(self.d_edit.text())
            noise = ssg.ar1_sim(alpha, self.Nt)
            components.append(noise)
            weights.append(d)

        if len(components) == 0:
            self.OutOfBounds = MessageWindow(
                "Activate at least one signal component!", "No Signal")
            return

        signal = ssg.assemble_signal(components, weights)

        # ----------------------------------------
        self.raw_signal = signal
        self.tvec = self.dt * np.arange(self.Nt)
        # ---------------------------------------

        if self.debug:
            print("created synth. signal:", self.raw_signal[:10])

        # plot right away
        self.set_initial_periods()
        self.set_initial_T_c()
        self.doPlot()
Exemple #27
0
    def do_the_loop(self):
        '''
        Uses the explicitly parsed self.wlet_pars 
        to control signal analysis settings.

        Takes general analysis Parameters

        self.parentDV.dt
        self.parentDV.time_unit

        and the DataFrame

        self.parentDV.df

        from the parent DataViewer.
        Reads additional settings from this Batch Process Window.

        '''

        EmptyRidge = 0

        if self.export_options.isChecked():
            OutPath = self.get_OutPath()
            if OutPath is None:
                return

        periods = np.linspace(self.wlet_pars['T_min'], self.wlet_pars['T_max'],
                              self.wlet_pars['step_num'])

        # retrieve batch settings
        power_thresh = self.get_thresh()
        rsmooth = self.get_ridge_smooth()

        # results get stored here
        ridge_results = {}
        df_fouriers = pd.DataFrame(index=periods)
        df_fouriers.index.name = 'period'

        for i, signal_id in enumerate(self.parentDV.df):

            # log to terminal
            print(f"processing {signal_id}..")

            # sets parentDV.raw_signal and parentDV.tvec
            succ = self.parentDV.vector_prep(signal_id)
            # ui silently passes over..
            if not succ:
                print(f"Can't process signal {signal_id}..")
                continue

            # detrend?!
            if self.parentDV.cb_use_detrended.isChecked():
                trend = self.parentDV.calc_trend()
                signal = self.parentDV.raw_signal - trend
            else:
                signal = self.parentDV.raw_signal

            # amplitude normalization?
            if self.parentDV.cb_use_envelope.isChecked():
                if self.debug:
                    print('Calculating envelope with L=', self.wlet_pars['L'])
                signal = pyboat.normalize_with_envelope(
                    signal, self.wlet_pars['L'], self.parentDV.dt)

            # compute the spectrum
            modulus, wlet = pyboat.compute_spectrum(signal, self.parentDV.dt,
                                                    periods)
            # get maximum ridge
            ridge = pyboat.get_maxRidge_ys(modulus)
            # generate time vector
            tvec = np.arange(len(signal)) * self.parentDV.dt
            # evaluate along the ridge
            ridge_data = pyboat.eval_ridge(ridge,
                                           wlet,
                                           signal,
                                           periods,
                                           tvec,
                                           power_thresh,
                                           smoothing_wsize=rsmooth)

            # from ridge thresholding..
            if ridge_data.empty:
                EmptyRidge += 1
            else:
                ridge_results[signal_id] = ridge_data

            # time average the spectrum, all have shape len(periods)!
            averaged_Wspec = np.mean(modulus, axis=1)
            df_fouriers[signal_id] = averaged_Wspec

            # -- Save out individual results --

            if self.cb_specs.isChecked():

                # plot spectrum and ridge
                ax_sig, ax_spec = pl.mk_signal_modulus_ax(
                    self.parentDV.time_unit)
                pl.plot_signal_modulus((ax_sig, ax_spec),
                                       tvec,
                                       signal,
                                       modulus,
                                       periods,
                                       p_max=self.wlet_pars['p_max'])
                pl.draw_Wavelet_ridge(ax_spec, ridge_data)
                plt.tight_layout()
                fname = os.path.join(OutPath, f'{signal_id}_wspec.png')
                if self.debug:
                    print(
                        f'Plotting and saving spectrum {signal_id} to {fname}')
                plt.savefig(fname, dpi=DPI)
                plt.close()

            if self.cb_specs_noridge.isChecked():

                # plot spectrum without ridge
                ax_sig, ax_spec = pl.mk_signal_modulus_ax(
                    self.parentDV.time_unit)
                pl.plot_signal_modulus((ax_sig, ax_spec),
                                       tvec,
                                       signal,
                                       modulus,
                                       periods,
                                       p_max=self.wlet_pars['p_max'])
                plt.tight_layout()
                fname = os.path.join(OutPath, f'{signal_id}_wspecNR.png')
                if self.debug:
                    print(
                        f'Plotting and saving spectrum {signal_id} to {fname}')
                plt.savefig(fname, dpi=DPI)
                plt.close()

            if self.cb_readout_plots.isChecked() and not ridge_data.empty:

                pl.plot_readout(ridge_data)
                fname = os.path.join(OutPath, f'{signal_id}_readout.png')
                if self.debug:
                    print(f'Plotting and saving {signal_id} to {fname}')
                plt.savefig(fname, dpi=DPI)
                plt.close()

            if self.cb_readout.isChecked() and not ridge_data.empty:

                fname = os.path.join(OutPath, f'{signal_id}_readout.csv')
                if self.debug:
                    print(f'Saving ridge reatout to {fname}')
                ridge_data.to_csv(fname,
                                  sep=',',
                                  float_format='%.3f',
                                  index=False)

            self.progress.setValue(i)

        if EmptyRidge > 0:
            self.NoRidges = MessageWindow(
                f'{EmptyRidge} ridge readouts entirely below threshold..',
                'Discarded ridges')

        return ridge_results, df_fouriers
Exemple #28
0
    def import_file(self):
        """
        Reads the values from the config grid
        and prepares kwargs for the pandas read_... functions

        NaN interpolation is done here if requested
        """

        kwargs = {}

        if self.cb_header.isChecked():
            header = None  # pandas will assign numeric column names
        else:
            header = "infer"

        if not self.cb_use_ext.isChecked():

            sep = self.sep_edit.text()
            # empty field
            if sep == "":
                sep = None
            kwargs["sep"] = sep
            if self.debug:
                print(f"Separator is {sep}, with type {type(sep)}")

        NaN_value = self.NaN_edit.text()
        # empty field
        if NaN_value == "":
            NaN_value = None
        if self.debug:
            print(f"NaN value is {NaN_value}, with type {type(NaN_value)}")

        # assemble key-words for pandas read_... functions
        kwargs["header"] = header
        kwargs["na_values"] = NaN_value

        if self.debug:
            print(f"kwargs for load_data: {kwargs}")

        # -----------------------------------------------------
        df, err_msg = load_data(debug=self.debug, **kwargs)
        if err_msg:
            self.error = MessageWindow(err_msg, "Loading error")
            return
        # -----------------------------------------------------

        if self.cb_NaN.isChecked():

            N_NaNs = df.isna().to_numpy().sum()
            if N_NaNs > 0:
                msg = f"Found {N_NaNs} missing values in total\nlinearly interpolating through.."
                self.Interpolation = MessageWindow(msg, "NaN Interpolation")

            else:
                self.Interpolation = MessageWindow("No missing values found!",
                                                   "NaN Interpolation")

            name = df.name
            df = interpol_NaNs(df)
            df.name = name  # restore name

        # initialize new DataViewer with the loaded data
        # doesn't help as ini window gets destroyed..
        self.parent.DataViewers[self.parent.nViewers] = DataViewer(
            data=df, debug=self.debug)
        self.parent.nViewers += 1

        self.close()
Exemple #29
0
    def save_out(self):

        dialog = QFileDialog()
        options = QFileDialog.Options()

        #----------------------------------------------------------
        default_name = os.getenv('HOME') + '/TFAres_' + str(self.signal_id)
        format_filter = "Text File (*.txt);; CSV ( *.csv);; Excel (*.xlsx)"
        #-----------------------------------------------------------
        file_name, sel_filter = dialog.getSaveFileName(self,
                                                       "Save as",
                                                       default_name,
                                                       format_filter,
                                                       '(*.txt)',
                                                       options=options)

        # dialog cancelled
        if not file_name:
            return

        file_ext = file_name.split('.')[-1]

        if self.DEBUG:
            print('selected filter:', sel_filter)
            print('out-path:', file_name)
            print('extracted extension:', file_ext)
            print('ridge data keys:', self.ridge_data.keys())

        if file_ext not in ['txt', 'csv', 'xlsx']:
            self.e = MessageWindow(
                "Ouput format not supported..\n" +
                "Please append .txt, .csv or .xlsx\n" + "to the file name!",
                "Unknown format")
            return

        # the write out calls
        float_format = '%.2f'  # still old style :/

        if file_ext == 'txt':
            self.ridge_data.to_csv(file_name,
                                   index=False,
                                   sep='\t',
                                   float_format=float_format)

        elif file_ext == 'csv':
            self.ridge_data.to_csv(file_name,
                                   index=False,
                                   sep=',',
                                   float_format=float_format)

        elif file_ext == 'xlsx':
            self.ridge_data.to_excel(file_name,
                                     index=False,
                                     float_format=float_format)

        else:
            if self.DEBUG:
                print("Something went wrong during save out..")
            return
        if self.DEBUG:
            print('Saved!')