Skip to content
Snippets Groups Projects
Commit 9c7bd30e authored by Andreas Hellerschmied's avatar Andreas Hellerschmied
Browse files

Merge branch 'develop' into 'master'

Cleaned and refactored code and set up a clean distributon (excluded...

See merge request hellerdev/lifescale_utils!4
parents f510d4fc 83e5b2f7
No related branches found
No related tags found
No related merge requests found
Showing
with 1339 additions and 91 deletions
......@@ -30,6 +30,8 @@ venv/
ENV/
env/
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
......
exclude lifescale/models/ls_run.py lifescale/scripts/run_gui.py
\ No newline at end of file
# lifescale_gui
# lifescale_utils
Data analysis tools for lifescale with GUI.
# Installation and setup
* **1. Create virtual environment (venv)**
* `python3 -m venv env`
* **2. Activate virtual environment**
* `source env/bin/activate`
* **3. Clone git repository to local machine**
* `git clone git@gitlab.com:hellerdev/lifescale_gui.git`
* `cd lifescale_gui`
* **4. Install required python packages using pip**
* `pip install -r requirements.txt`
## Installation issues on Ubuntu (20.04):
After just installing PyQt5 with pip3 the following error occurred when trying to actually run a PyQt GUI: qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This issue was resolved by installing the QT dev tools (Designer, etc.):
sudo apt-get install qttools5-dev-tools
# Test installation with setuptools
With command line interface.
* **1. Configure setup.py**
* Define entry points (*console_scripts*)
* **2. Activate virtual environment**
* e.g. `source env/bin/activate`
* **3. Run setup.py**
* `python3 setup.py develop`
## Using make
`python3 setup.py develop`
# Run application on Windows and create a stand-alone Windows executable file:
TODO
# Comments on requirements.txt file:
* Two entries can be deleted:
* -e git+git@gitlab.com:Heller182/grav.git@fe528c0769502e84a06be67a742032cacfd386df#egg=gravtools
* pkg-resources==0.0.0 (created due a bug when using Linux, see: https://stackoverflow.com/questions/39577984/what-is-pkg-resources-0-0-0-in-output-of-pip-freeze-command)
# Create HTML documentation with sphinx:
Run make in the gravtools/doc directory:
* `>>>make html_doc`
# Guidelines and conventions
## Code style:
* Respect the PEP conventions on python coding!
* PEP 8 -- Style Guide for Python Code: https://www.python.org/dev/peps/pep-0008/
* The maximum line length is 120 characters
* Use **type hints**: https://www.python.org/dev/peps/pep-0484/
* Use docstrings according to the numpy standard: https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
* They are useful to generate the documentation automatically
* Example: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html
* Comment code, if necessary!
* Use English language for the code, docstrings and comments
* German is allowed for user interfaces (GUI, command line), although English is preferred
## Documentation and docstring style
* The API reference is created with sphinx (https://www.sphinx-doc.org/).
* Docstrings have to follow the numpy standard, see: https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
* Examples: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html
* Package documentation via docstring in __ini__.py files
* Module documentation via docstring at first lines of py-file
* Documentation of classes, class methods and functions via docstrings
## Command line interface and executable scripts
* The command line interface is realized via entry points (console_scripts) in setuptools (python packaging tool)
* Input arguments are handled with argparse
* The code is located in the command_line module (gravtools/command_line.py)
* Executable scripts are located in gravtools/scripts
## Dependancies
* Required python packages are listed in requirements.txt
* created with `>>>pip freeze > requirements.txt`
## Version control with GIT
* Gitlab repository: https://gitlab.com/Heller182/grav
* Branching model:
* **master** branch: Current release version
* **develop** branch: Current working version.
* All team members merge their feature branches into develop (merge request via gitlab)
* Make sure that the develop branch contains a fully functional version of the code!
* **feature** branches: Branches of develop for the implementation of new features and other changes.
* Code changes only in feature branches!
* Naming convention: feature_<description of change/feature>, e.g. feature_new_tide_model
* Use gitignore files to prevent any data files (except example files), IDE control files, compiled python code, etc. from being stored in the GIT repository
* Generally rule: Ignore everything in a directory and define explicit exceptions!
## Packaging and distribution
* With setuptools
# Command line programs:
## ls2csv
The program *ls2csv* reads the content of the xlsm files written by lifescale units, parses the data and writes them to three csv
files (where `[run-name]` is the name from the settings sheet):
* `Masses_Vibrio_[run-name].csv`: Data series from the sheet AcquisitionIntervals.
* `Metadata_[run-name].csv`: Data from the sheet PanelData.
* `SampleSummary_[run-name].csv`: Data from the sheet IntervalAnalysis plus sample related data from AcquisitionIntervals.
### Usage:
```
ls2csv -i [path and nale of xlsm file] -o [outpur directory] [-s] [-nv]
options:
-h, --help show this help message and exit
-i INPUT_XLSM, --input-xlsm INPUT_XLSM
Path and name of the input xlsm file created by
lifescale. (default: None)
-o OUT_DIR, --out-dir OUT_DIR
Output directory for the CSV files. (default: None)
-nv, --not-verbose Disable command line status messages. (default: False)
-s, --sample-stats Calculate sample statistics of masses (median, std.
deviation, quartiles, interquartile range) and add
them to the SampleSummary output CSV file (columns:
Mass_median, Mass_std, Mass_q25, Mass_q75,Mass_iqr).
(default: False)
-t, --sort-masses-by-time
Sort data in the Masses CSV file by acquisition time.
(default: False)
```
# License and copyright
Copyright (C) 2022 Andreas Hellerschmied (<heller182@gmx.at>)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
# Current pgm:
## Input data (naive_peaks.py):
- raw data files: binary data (required)
- metadata: csv file that holds the information of the PanelData tab in the according .xlsm file
- jason file with settings:
- raw data folder
- processing settings
# Questions:
- Which license?
- Is it OK for Joseph Elsherbini to use/change his code?
- Is a "raw data viewer" needed to show the content of the binary raw data files?
- Individual files, or from one experiment?
- Load to pandas DF and show in table in GUI?
- Is editing required?
- Are any search options needed?
- Format conversion, e.g. to csv files needed?
- Should there be the possibility to store the current GUI settings (data and processing parameters, etc.)
- Should there be the possibility to load default parameters and/or previously saved parameters (e.g. from json file)?
- Is the json file required in the current version, e.g. for documentation (processing parameters, etc.) or further analysis?
- Are there any default values for the processing parameters? Should they be stored anywhere (e.g. json file)?
- Standard values defined in pgm code (e.g. parameters.py file). These parameters are loaded on the initial start
- Save/Load parameters from GUI to json file => Define "standard parameter set" that way
## Processing:
- Is the input data (raw data) always organized in the same way, i.e.: Raw data folder that contains data files with the
file names containing the exper. name date and time?
- Where do we get the following parameters (listed in drop down menu) - from the filenames?
- Experiment name
- Date
- Time
- should directly the .xlsm file (PanelData tab) be used instead of an .csv file that holds identical information?
- What is the actual output of the lifescale devise?
- raw data?
- xlsm files with metadata?
## For plotting and analysis:
- Is additional data required from other sources, e.g. the .xlsm files?
- What should be plotted/analyzed/calculated?
"""LifeScale utils is a utility program for handling data output.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
:Authors:
Andreas Hellerschmied (heller182@gmx.at)
"""
__version__ = '0.0.3'
__author__ = 'Andreas Hellerschmied'
__git_repo__ = 'tba'
__email__ = 'heller182@gmx.at'
__copyright__ = '(c) 2022 Andreas Hellerschmied'
"""LifeScale utils command line interface module.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
:Authors:
Andreas Hellerschmied (heller182@gmx.at)
"""
\ No newline at end of file
"""Command line interface of lifescale utils.
Copyright (C) 2022 Andreas Hellerschmied <heller182@gmx.at>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from lifescale.scripts.ls2csv import ls2csv as ls2csv_main
import argparse
import os
def is_file(filename):
"""Check, whether the input string is the path to an existing file."""
if os.path.isfile(filename):
return filename
raise argparse.ArgumentTypeError("'{}' is not a valid file.".format(filename))
def is_dir(pathname):
"""Check, whether the input string is a valid and existing filepath."""
if os.path.exists(pathname):
return pathname
raise argparse.ArgumentTypeError("'{}' is not a valid directory.".format(pathname))
def ls2csv():
"""Command line interface including argument parser for the lifescale2csv converter."""
parser = argparse.ArgumentParser(prog="ls2csv",
description="Conversion from lifescale xlsm output to csv files",
epilog="The ls2csv converter loads and parses xlsm files created by the lifescale "
"unit. It writes several csv files to the output directory that contain "
"extracted data from the input xlsm file in an easily readable way.",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("-i", "--input-xlsm", type=is_file, required=True, help="Path and name of the input xlsm file "
"created by "
"lifescale.")
parser.add_argument("-o", "--out-dir", type=is_dir, required=True, help="Output directory for the CSV files.")
parser.add_argument("-nv", "--not-verbose", required=False, help="Disable command line status messages.",
action='store_true')
parser.add_argument("-s", "--sample-stats", required=False, help="Calculate sample statistics of masses (median, "
"std. deviation, quartiles, interquartile range) "
"and add them to the "
"SampleSummary output CSV file (columns: "
"Mass_median, Mass_std, Mass_q25, Mass_q75,"
"Mass_iqr).",
action='store_true')
parser.add_argument("-t", "--sort-masses-by-time", required=False, help="Sort data in the Masses CSV file by "
"acquisition time.",
action='store_true')
args = parser.parse_args()
verbose = not args.not_verbose
return ls2csv_main(xlsm_filename=args.input_xlsm,
output_dir=args.out_dir,
sample_stats=args.sample_stats,
sort_by_time=args.sort_masses_by_time,
verbose=verbose)
if __name__ == '__main__':
"""Main function for debugging and testing."""
ls2csv()
# Form implementation generated from reading ui file 'lifescale/gui/MainWindow.ui'
#
# Created by: PyQt6 UI code generator 6.2.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt6 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(992, 616)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.tabWidget_Main = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget_Main.setObjectName("tabWidget_Main")
self.tab_peaks = QtWidgets.QWidget()
self.tab_peaks.setObjectName("tab_peaks")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab_peaks)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.groupBox_data = QtWidgets.QGroupBox(self.tab_peaks)
self.groupBox_data.setObjectName("groupBox_data")
self.formLayout = QtWidgets.QFormLayout(self.groupBox_data)
self.formLayout.setObjectName("formLayout")
self.label_data_rawData = QtWidgets.QLabel(self.groupBox_data)
self.label_data_rawData.setObjectName("label_data_rawData")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_data_rawData)
self.horizontalLayout_data_rawData = QtWidgets.QHBoxLayout()
self.horizontalLayout_data_rawData.setObjectName("horizontalLayout_data_rawData")
self.lineEdit_data_rawData = QtWidgets.QLineEdit(self.groupBox_data)
self.lineEdit_data_rawData.setObjectName("lineEdit_data_rawData")
self.horizontalLayout_data_rawData.addWidget(self.lineEdit_data_rawData)
self.pushButton_data_rawData = QtWidgets.QPushButton(self.groupBox_data)
self.pushButton_data_rawData.setObjectName("pushButton_data_rawData")
self.horizontalLayout_data_rawData.addWidget(self.pushButton_data_rawData)
self.formLayout.setLayout(0, QtWidgets.QFormLayout.ItemRole.FieldRole, self.horizontalLayout_data_rawData)
self.label_data_metadataFile = QtWidgets.QLabel(self.groupBox_data)
self.label_data_metadataFile.setObjectName("label_data_metadataFile")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_data_metadataFile)
self.horizontalLayout_data_metadataFile = QtWidgets.QHBoxLayout()
self.horizontalLayout_data_metadataFile.setObjectName("horizontalLayout_data_metadataFile")
self.lineEdit_data_metadataFile = QtWidgets.QLineEdit(self.groupBox_data)
self.lineEdit_data_metadataFile.setObjectName("lineEdit_data_metadataFile")
self.horizontalLayout_data_metadataFile.addWidget(self.lineEdit_data_metadataFile)
self.pushButton_data_metadataFile = QtWidgets.QPushButton(self.groupBox_data)
self.pushButton_data_metadataFile.setObjectName("pushButton_data_metadataFile")
self.horizontalLayout_data_metadataFile.addWidget(self.pushButton_data_metadataFile)
self.formLayout.setLayout(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.horizontalLayout_data_metadataFile)
self.label_data_outputFolder = QtWidgets.QLabel(self.groupBox_data)
self.label_data_outputFolder.setObjectName("label_data_outputFolder")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_data_outputFolder)
self.horizontalLayout_data_outputFolder = QtWidgets.QHBoxLayout()
self.horizontalLayout_data_outputFolder.setObjectName("horizontalLayout_data_outputFolder")
self.lineEdit_data_outputFolder = QtWidgets.QLineEdit(self.groupBox_data)
self.lineEdit_data_outputFolder.setObjectName("lineEdit_data_outputFolder")
self.horizontalLayout_data_outputFolder.addWidget(self.lineEdit_data_outputFolder)
self.pushButton_data_outputFolder = QtWidgets.QPushButton(self.groupBox_data)
self.pushButton_data_outputFolder.setObjectName("pushButton_data_outputFolder")
self.horizontalLayout_data_outputFolder.addWidget(self.pushButton_data_outputFolder)
self.formLayout.setLayout(2, QtWidgets.QFormLayout.ItemRole.FieldRole, self.horizontalLayout_data_outputFolder)
self.label_data_selectExperiment = QtWidgets.QLabel(self.groupBox_data)
self.label_data_selectExperiment.setObjectName("label_data_selectExperiment")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_data_selectExperiment)
self.comboBox_data_selectExperiment = QtWidgets.QComboBox(self.groupBox_data)
self.comboBox_data_selectExperiment.setObjectName("comboBox_data_selectExperiment")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.ItemRole.FieldRole, self.comboBox_data_selectExperiment)
self.verticalLayout_2.addWidget(self.groupBox_data)
self.groupBox_processingParameters = QtWidgets.QGroupBox(self.tab_peaks)
self.groupBox_processingParameters.setObjectName("groupBox_processingParameters")
self.formLayout_2 = QtWidgets.QFormLayout(self.groupBox_processingParameters)
self.formLayout_2.setObjectName("formLayout_2")
self.label_massTransformation = QtWidgets.QLabel(self.groupBox_processingParameters)
self.label_massTransformation.setObjectName("label_massTransformation")
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_massTransformation)
self.doubleSpinBox_massTransformation = QtWidgets.QDoubleSpinBox(self.groupBox_processingParameters)
self.doubleSpinBox_massTransformation.setDecimals(6)
self.doubleSpinBox_massTransformation.setObjectName("doubleSpinBox_massTransformation")
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.ItemRole.FieldRole, self.doubleSpinBox_massTransformation)
self.label_massCutoff = QtWidgets.QLabel(self.groupBox_processingParameters)
self.label_massCutoff.setObjectName("label_massCutoff")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_massCutoff)
self.doubleSpinBox_massCutoff = QtWidgets.QDoubleSpinBox(self.groupBox_processingParameters)
self.doubleSpinBox_massCutoff.setDecimals(1)
self.doubleSpinBox_massCutoff.setObjectName("doubleSpinBox_massCutoff")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.doubleSpinBox_massCutoff)
self.label_peakWidthCutoff = QtWidgets.QLabel(self.groupBox_processingParameters)
self.label_peakWidthCutoff.setObjectName("label_peakWidthCutoff")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_peakWidthCutoff)
self.doubleSpinBox_peakWidthCutoff = QtWidgets.QDoubleSpinBox(self.groupBox_processingParameters)
self.doubleSpinBox_peakWidthCutoff.setDecimals(1)
self.doubleSpinBox_peakWidthCutoff.setObjectName("doubleSpinBox_peakWidthCutoff")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.ItemRole.FieldRole, self.doubleSpinBox_peakWidthCutoff)
self.label_peakDistanceCutoff = QtWidgets.QLabel(self.groupBox_processingParameters)
self.label_peakDistanceCutoff.setObjectName("label_peakDistanceCutoff")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_peakDistanceCutoff)
self.doubleSpinBox_peakDistanceCutoff = QtWidgets.QDoubleSpinBox(self.groupBox_processingParameters)
self.doubleSpinBox_peakDistanceCutoff.setDecimals(1)
self.doubleSpinBox_peakDistanceCutoff.setObjectName("doubleSpinBox_peakDistanceCutoff")
self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.ItemRole.FieldRole, self.doubleSpinBox_peakDistanceCutoff)
self.verticalLayout_2.addWidget(self.groupBox_processingParameters)
self.pushButton_run = QtWidgets.QPushButton(self.tab_peaks)
self.pushButton_run.setObjectName("pushButton_run")
self.verticalLayout_2.addWidget(self.pushButton_run)
self.tabWidget_Main.addTab(self.tab_peaks, "")
self.tab_analysis = QtWidgets.QWidget()
self.tab_analysis.setObjectName("tab_analysis")
self.tabWidget_Main.addTab(self.tab_analysis, "")
self.verticalLayout.addWidget(self.tabWidget_Main)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 992, 22))
self.menubar.setObjectName("menubar")
self.menuOptions = QtWidgets.QMenu(self.menubar)
self.menuOptions.setObjectName("menuOptions")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionSave_current_GUI_parameters_json = QtGui.QAction(MainWindow)
self.actionSave_current_GUI_parameters_json.setObjectName("actionSave_current_GUI_parameters_json")
self.actionLoad_GUI_parameters_json = QtGui.QAction(MainWindow)
self.actionLoad_GUI_parameters_json.setObjectName("actionLoad_GUI_parameters_json")
self.actionLoad_default_parameters = QtGui.QAction(MainWindow)
self.actionLoad_default_parameters.setObjectName("actionLoad_default_parameters")
self.menuOptions.addAction(self.actionSave_current_GUI_parameters_json)
self.menuOptions.addAction(self.actionLoad_GUI_parameters_json)
self.menuOptions.addAction(self.actionLoad_default_parameters)
self.menubar.addAction(self.menuOptions.menuAction())
self.retranslateUi(MainWindow)
self.tabWidget_Main.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "lifescale tools"))
self.groupBox_data.setTitle(_translate("MainWindow", "Data"))
self.label_data_rawData.setText(_translate("MainWindow", "Raw data folder"))
self.pushButton_data_rawData.setText(_translate("MainWindow", "Browse"))
self.label_data_metadataFile.setText(_translate("MainWindow", "Metadata file (optional)"))
self.pushButton_data_metadataFile.setText(_translate("MainWindow", "Browse"))
self.label_data_outputFolder.setText(_translate("MainWindow", "Output folder"))
self.pushButton_data_outputFolder.setText(_translate("MainWindow", "Browse"))
self.label_data_selectExperiment.setText(_translate("MainWindow", "Select Experiment"))
self.groupBox_processingParameters.setTitle(_translate("MainWindow", "Processing parameters"))
self.label_massTransformation.setText(_translate("MainWindow", "Mass transformation [fg/Hz]"))
self.label_massCutoff.setText(_translate("MainWindow", "Mass cutoff [fg]"))
self.label_peakWidthCutoff.setText(_translate("MainWindow", "Peak width cutoff [???]"))
self.label_peakDistanceCutoff.setText(_translate("MainWindow", "Peak distance cutoff [??]"))
self.pushButton_run.setText(_translate("MainWindow", "Run"))
self.tabWidget_Main.setTabText(self.tabWidget_Main.indexOf(self.tab_peaks), _translate("MainWindow", "Mass Peaks"))
self.tabWidget_Main.setTabText(self.tabWidget_Main.indexOf(self.tab_analysis), _translate("MainWindow", "Analysis"))
self.menuOptions.setTitle(_translate("MainWindow", "Options"))
self.actionSave_current_GUI_parameters_json.setText(_translate("MainWindow", "Save current GUI parameters (json)"))
self.actionLoad_GUI_parameters_json.setText(_translate("MainWindow", "Load GUI parameters (json)"))
self.actionLoad_default_parameters.setText(_translate("MainWindow", "Load default parameters"))
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>992</width>
<height>616</height>
</rect>
</property>
<property name="windowTitle">
<string>lifescale tools</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget_Main">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_peaks">
<attribute name="title">
<string>Mass Peaks</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_data">
<property name="title">
<string>Data</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_data_rawData">
<property name="text">
<string>Raw data folder</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_data_rawData">
<item>
<widget class="QLineEdit" name="lineEdit_data_rawData"/>
</item>
<item>
<widget class="QPushButton" name="pushButton_data_rawData">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_data_metadataFile">
<property name="text">
<string>Metadata file (optional)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_data_metadataFile">
<item>
<widget class="QLineEdit" name="lineEdit_data_metadataFile"/>
</item>
<item>
<widget class="QPushButton" name="pushButton_data_metadataFile">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_data_outputFolder">
<property name="text">
<string>Output folder</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_data_outputFolder">
<item>
<widget class="QLineEdit" name="lineEdit_data_outputFolder"/>
</item>
<item>
<widget class="QPushButton" name="pushButton_data_outputFolder">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_data_selectExperiment">
<property name="text">
<string>Select Experiment</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBox_data_selectExperiment"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_processingParameters">
<property name="title">
<string>Processing parameters</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_massTransformation">
<property name="text">
<string>Mass transformation [fg/Hz]</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_massTransformation">
<property name="decimals">
<number>6</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_massCutoff">
<property name="text">
<string>Mass cutoff [fg]</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_massCutoff">
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_peakWidthCutoff">
<property name="text">
<string>Peak width cutoff [???]</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_peakWidthCutoff">
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_peakDistanceCutoff">
<property name="text">
<string>Peak distance cutoff [??]</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_peakDistanceCutoff">
<property name="decimals">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_run">
<property name="text">
<string>Run</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_analysis">
<attribute name="title">
<string>Analysis</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>992</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuOptions">
<property name="title">
<string>Options</string>
</property>
<addaction name="actionSave_current_GUI_parameters_json"/>
<addaction name="actionLoad_GUI_parameters_json"/>
<addaction name="actionLoad_default_parameters"/>
</widget>
<addaction name="menuOptions"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionSave_current_GUI_parameters_json">
<property name="text">
<string>Save current GUI parameters (json)</string>
</property>
</action>
<action name="actionLoad_GUI_parameters_json">
<property name="text">
<string>Load GUI parameters (json)</string>
</property>
</action>
<action name="actionLoad_default_parameters">
<property name="text">
<string>Load default parameters</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
File moved
import sys
import os
from PyQt6.QtWidgets import QApplication, QMainWindow
from lifescale.gui.MainWindow import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
"""Main Window of the application."""
def __init__(self):
"""Initializer."""
# GUI:
super().__init__()
self.setupUi(self)
# Connect signals and slots:
# Set up GUI items and widgets:
# Init models:
def main():
"""Main program to start the GUI."""
# Create the application
app = QApplication(sys.argv)
# Create and show the application's main window
main_window = MainWindow()
main_window.show()
# Run the application's main loop:
sys.exit(
app.exec()) # exit or error code of Qt (app.exec_) is passed to sys.exit. Terminates pgm with standard python method
if __name__ == "__main__":
"""Main Program."""
main()
"""LifeScale utils objects module.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
:Authors:
Andreas Hellerschmied (heller182@gmx.at)
"""
\ No newline at end of file
This diff is collapsed.
"""Modelling a LifeScale run
Copyright (C) 2022 Andreas Hellerschmied <heller182@gmx.at>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import datetime as dt
import pytz
import numpy as np
import pickle
import os
import sys
import pandas as pd
# from gravtools.models.lsm import LSM
class LSRun:
"""LifeScale run object.
A LS run contains:
- run name and description
- input data
- settings
Attributes
----------
run_name : str
Name of the lsm run.
output_directory : str
Path to output directory (all output files are stored there).
pgm_version : str
Version of the program.
"""
def __init__(self,
campaign_name,
output_directory,
surveys=None, # Always use non-mutable default arguments!
stations=None, # Always use non-mutable default arguments!
lsm_runs=None, # Always use non-mutable default arguments!
ref_delta_t_dt=None # Reference time for drift determination
):
"""
Parameters
"""
\ No newline at end of file
"""LifeScale utils scripts module.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
:Authors:
Andreas Hellerschmied (heller182@gmx.at)
"""
\ No newline at end of file
"""Conversion program from xlsm to csv.
Copyright (C) 2022 Andreas Hellerschmied <heller182@gmx.at>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from lifescale.models.ls_data import LSData
def ls2csv(xlsm_filename, output_dir, sample_stats=True, sort_by_time=False, verbose=True):
"""Convert lifescale output file (xlsm) to csv files."""
ls_data = LSData.from_xlsm_file(input_xlsm_filename=xlsm_filename, verbose=verbose)
if sample_stats:
ls_data.calc_sample_statistics(verbose=verbose)
ls_data.export_csv_files(output_dir, sort_by_time=sort_by_time, verbose=verbose)
"""Start the lifescale GUI from here!
Copyright (C) 2022 Andreas Hellerschmied <heller182@gmx.at>
"""
from lifescale.gui.gui_main import main
def run_gui():
"""Start the GUI."""
main()
if __name__ == "__main__":
"""Main Program."""
run_gui()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment