Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • software_public/passoft/sohstationviewer
1 result
Show changes
Commits on Source (49)
Showing
with 98 additions and 91 deletions
...@@ -11,3 +11,15 @@ History ...@@ -11,3 +11,15 @@ History
-------- --------
* Fixed a problem with SOHViewer not fitting on smaller resolutions * Fixed a problem with SOHViewer not fitting on smaller resolutions
2024.2.0.0
--------
* Migrated GUI library from PySide2 to PySide6
* Database editor is now functional
* RT130's mass-position data (i.e. data stream 9 data) now does not generate
an Event channel
* Input to minimum gap length editor is now constrained to only accept numeric
input
* Improved the ability to calculate the size of a data set
* General bug fixes
package: package:
name: sohviewer name: sohviewer
version: 2023.1.0.1 version: 2024.2.0.0
source: source:
path: ../ path: ../
...@@ -17,7 +17,7 @@ requirements: ...@@ -17,7 +17,7 @@ requirements:
- python >=3.9 - python >=3.9
- numpy>=1.23.0 - numpy>=1.23.0
- obspy >=1.3.0 - obspy >=1.3.0
- PySide2 - PySide6>=6.5.2
- matplotlib>=3.5.0 - matplotlib>=3.5.0
test: test:
......
...@@ -34,7 +34,7 @@ setup( ...@@ -34,7 +34,7 @@ setup(
install_requires=[ install_requires=[
'numpy>=1.23.0', 'numpy>=1.23.0',
'obspy>=1.3.0', 'obspy>=1.3.0',
'PySide2', 'PySide6>=6.5.2',
'matplotlib>=3.5.0', 'matplotlib>=3.5.0',
], ],
setup_requires=[], setup_requires=[],
...@@ -48,9 +48,9 @@ setup( ...@@ -48,9 +48,9 @@ setup(
long_description=readme + '\n\n' + history, long_description=readme + '\n\n' + history,
include_package_data=True, include_package_data=True,
keywords='sohstationviewer', keywords='sohstationviewer',
name='sohstationviewer', name='sohviewer',
packages=find_packages(include=['sohstationviewer*']), packages=find_packages(include=['sohstationviewer*']),
url='https://git.passcal.nmt.edu/software_public/passoft/sohstationviewer', url='https://git.passcal.nmt.edu/software_public/passoft/sohstationviewer',
version='2023.1.0.1', version='2024.2.0.0',
zip_safe=False, zip_safe=False,
) )
import configparser import configparser
from pathlib import Path from pathlib import Path
from PySide2 import QtCore from PySide6 import QtCore
from sohstationviewer.conf import constants from sohstationviewer.conf import constants
from sohstationviewer.conf.constants import CONFIG_PATH from sohstationviewer.conf.constants import CONFIG_PATH
......
from typing import Literal from typing import Literal
# The current version of SOHStationViewer # The current version of SOHStationViewer
SOFTWARE_VERSION = '2023.1.0.1' SOFTWARE_VERSION = '2024.2.0.0'
# waveform pattern # waveform pattern
WF_1ST = 'A-HLM-V' WF_1ST = 'A-HLM-V'
......
...@@ -43,11 +43,11 @@ def format_time(time: Union[UTCDateTime, float], date_mode: str, ...@@ -43,11 +43,11 @@ def format_time(time: Union[UTCDateTime, float], date_mode: str,
return ret return ret
def get_title(key: Union[str, Tuple[str, int]], min_time: float, def get_title(data_set_id: Union[str, Tuple[str, int]], min_time: float,
max_time: float, date_mode: str) -> str: max_time: float, date_mode: str) -> str:
""" """
Create title for the plot. Create title for the plot.
:param key: str or (str, str) sta_id for mseed, (unit_id, exp_no) for rt130 :param data_set_id: sta_id for mseed, (unit_id, exp_no) for rt130
:param min_time: start time of the plot :param min_time: start time of the plot
:param max_time: end time of the plot :param max_time: end time of the plot
:param date_mode: format of date :param date_mode: format of date
...@@ -56,7 +56,7 @@ def get_title(key: Union[str, Tuple[str, int]], min_time: float, ...@@ -56,7 +56,7 @@ def get_title(key: Union[str, Tuple[str, int]], min_time: float,
diff = max_time - min_time diff = max_time - min_time
hours = diff / 3600 hours = diff / 3600
return ("%s %s to %s (%s)" % return ("%s %s to %s (%s)" %
(key, (data_set_id,
format_time(min_time, date_mode, "HH:MM:SS"), format_time(min_time, date_mode, "HH:MM:SS"),
format_time(max_time, date_mode, "HH:MM:SS"), format_time(max_time, date_mode, "HH:MM:SS"),
round(hours, 2)) round(hours, 2))
......
...@@ -9,9 +9,9 @@ import re ...@@ -9,9 +9,9 @@ import re
from pathlib import Path from pathlib import Path
from typing import List, Optional, Dict, Tuple, Union, BinaryIO from typing import List, Optional, Dict, Tuple, Union, BinaryIO
from PySide2.QtCore import QEventLoop, Qt from PySide6.QtCore import QEventLoop, Qt
from PySide2.QtGui import QCursor from PySide6.QtGui import QCursor
from PySide2.QtWidgets import QTextBrowser, QApplication from PySide6.QtWidgets import QTextBrowser, QApplication
from obspy.io import reftek from obspy.io import reftek
from obspy import UTCDateTime from obspy import UTCDateTime
......
...@@ -9,8 +9,8 @@ from datetime import datetime ...@@ -9,8 +9,8 @@ from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Tuple, List, Union, Dict from typing import Tuple, List, Union, Dict
from PySide2 import QtCore from PySide6 import QtCore
from PySide2.QtWidgets import QTextBrowser from PySide6.QtWidgets import QTextBrowser
from obspy import UTCDateTime from obspy import UTCDateTime
...@@ -252,8 +252,8 @@ def apply_convert_factor(c_data: dict, convert_factor: float): ...@@ -252,8 +252,8 @@ def apply_convert_factor(c_data: dict, convert_factor: float):
=> unit data * convertFactor= data *150/1000 V => unit data * convertFactor= data *150/1000 V
:param c_data: data of the channel which includes down-sampled :param c_data: data of the channel which includes down-sampled
data in keys 'times' and 'data'. Refer to DataTypeModel.__init__. data in keys 'times' and 'data'.
soh_data[key][chan_id] Refer to data_dict in data_structures.MD
:param convert_factor: convertFactor field retrieved from :param convert_factor: convertFactor field retrieved from
db table Channels for this channel db table Channels for this channel
""" """
......
...@@ -2,20 +2,22 @@ ...@@ -2,20 +2,22 @@
basic executing database functions basic executing database functions
""" """
import sqlite3 import sqlite3
from typing import Sequence, Union
from sohstationviewer.conf.dbSettings import dbConf from sohstationviewer.conf.dbSettings import dbConf
def execute_db(sql): def execute_db(sql: str, parameters: Union[dict, Sequence] = ()):
""" """
Execute or fetch data from DB Execute or fetch data from DB
:param sql: str - request string to execute or fetch data from database :param sql: str - request string to execute or fetch data from database
:param parameters: the parameters used for executing parameterized queries
:return rows: [(str/int,] - result of querying DB :return rows: [(str/int,] - result of querying DB
""" """
conn = sqlite3.connect(dbConf['dbpath']) conn = sqlite3.connect(dbConf['dbpath'])
cur = conn.cursor() cur = conn.cursor()
try: try:
cur.execute(sql) cur.execute(sql, parameters)
except sqlite3.OperationalError as e: except sqlite3.OperationalError as e:
print("sqlite3.OperationalError:%s\n\tSQL: %s" % (str(e), sql)) print("sqlite3.OperationalError:%s\n\tSQL: %s" % (str(e), sql))
rows = cur.fetchall() rows = cur.fetchall()
......
No preview for this file type
...@@ -36,7 +36,7 @@ The home button can be used to return to this page at any time. ...@@ -36,7 +36,7 @@ The home button can be used to return to this page at any time.
+ [Save Plots](14%20_%20Save%20Plots.help.md) + [Save Plots](14%20_%20Save%20Plots.help.md)
+ [Plot Different Key](15%20_%20Plot%20Different%20Key.help.md) + [Plot Different Data Set ID](15%20_%20Plot%20Different%20Data%20Set%20ID.help.md)
+ [Search SOH n LOG](20%20_%20Search%20SOH%20n%20LOG.help.md) + [Search SOH n LOG](20%20_%20Search%20SOH%20n%20LOG.help.md)
......
## Plotting different data set id
There is a chance that the selected data set has more than one id defined by
station id in MSeed data or (serial number, network code) in Reftek.
<br />
Button "Plot Different Data Set ID" has been implemented to allow user select a
different data set id after data from selected files are plotted.
<br />
<br />
This button is disabled by default.
<br />
<br />
<img alt="Plot Different Data Set ID button disabled" src="images/plot_different_data_set_id/plot_different_data_set_id_button_disabled.png" height="60" />
<br />
<br />
After data are loaded, if the data set has more than one id, user will be
asked to select one data set id to plot. User will click on one of the data set id
buttons to plot a data set.
<br />
<br />
<img alt="Select One Data Set ID to Display dialog" src="images/plot_different_data_set_id/select_one_data_set_id_to_display_dlg.png" height="120" />
<br />
<br />
The button "Plot Different Data Set ID" will be enabled.
<br />
<br />
<img alt="Plot Different Data Set ID button enabled" src="images/plot_different_data_set_id/plot_different_data_set_id_button_enabled.png" height="60" />
<br />
<br />
Now user can click on the button to access a dialog that allows user to select
another data set id for plotting. User can click on one of the id buttons to plot
or click Abort to cancel.
<br />
<br />
<img alt="Select a Different Data Set ID to Replot" src="images/plot_different_data_set_id/select_a_different_data_set_id_to_replot_dlg.png" height="110" />
<br />
<br />
\ No newline at end of file
## Plotting different key
There is a chance that the selected data set has more than one key defined by
station id in MSeed data or (serial number, network code) in Reftek.
<br />
Button "Plot Different Key" has been implemented to allow user select a
different key after data from selected files are plotted.
<br />
<br />
This button is disabled by default.
<br />
<br />
<img alt="Plot Different Key button disabled" src="images/plot_different_key/plot_different_key_button_disabled.png" height="60" />
<br />
<br />
After data are loaded, if the data set has more than one key, user will be
asked to select one key to plot. User will click on one of the key buttons to plot a data set.
<br />
<br />
<img alt="Select One Key to Display dialog" src="images/plot_different_key/select_one_key_to_display_dlg.png" height="120" />
<br />
<br />
The button "Plot Different Key" will be enabled.
<br />
<br />
<img alt="Plot Different Key button enabled" src="images/plot_different_key/plot_different_key_button_enabled.png" height="60" />
<br />
<br />
Now user can click on the button to access a dialog that allows user to select
another key for plotting. User can click on one of the key buttons to plot that
key's data set or click Abort to cancel.
<br />
<br />
<img alt="Select a Different Key to Replot" src="images/plot_different_key/select_a_different_key_to_replot_dlg.png" height="110" />
<br />
<br />
\ No newline at end of file
#!/usr/bin/env python3 #!/usr/bin/env python3
import platform
import os import os
import sys import sys
import traceback import traceback
from pathlib import Path from pathlib import Path
from PySide2 import QtWidgets from PySide6 import QtWidgets
from PySide2.QtGui import QGuiApplication from PySide6.QtWidgets import QMessageBox
from PySide2.QtWidgets import QMessageBox
from sohstationviewer.view.main_window import MainWindow from sohstationviewer.view.main_window import MainWindow
from sohstationviewer.conf.config_processor import ( from sohstationviewer.conf.config_processor import (
...@@ -15,16 +13,6 @@ from sohstationviewer.conf.config_processor import ( ...@@ -15,16 +13,6 @@ from sohstationviewer.conf.config_processor import (
BadConfigError, BadConfigError,
) )
# Enable Layer-backing for MacOs version >= 11
# Only needed if using the pyside2 library with version>=5.15.
# Layer-backing is always enabled in pyside6.
os_name, version, *_ = platform.platform().split('-')
# if os_name == 'macOS' and version >= '11':
# mac OSX 11.6 appear to be 10.16 when read with python and still required this
# environment variable
if os_name == 'macOS':
os.environ['QT_MAC_WANTS_LAYER'] = '1'
def fix_relative_paths() -> None: def fix_relative_paths() -> None:
""" """
...@@ -74,12 +62,12 @@ def check_if_user_want_to_reset_config() -> bool: ...@@ -74,12 +62,12 @@ def check_if_user_want_to_reset_config() -> bool:
bad_config_dialog.setDetailedText(traceback.format_exc()) bad_config_dialog.setDetailedText(traceback.format_exc())
bad_config_dialog.setInformativeText('Do you want to reset the config ' bad_config_dialog.setInformativeText('Do you want to reset the config '
'file?') 'file?')
bad_config_dialog.setStandardButtons(QMessageBox.Ok | bad_config_dialog.setStandardButtons(QMessageBox.StandardButton.Ok |
QMessageBox.Close) QMessageBox.StandardButton.Close)
bad_config_dialog.setDefaultButton(QMessageBox.Ok) bad_config_dialog.setDefaultButton(QMessageBox.StandardButton.Ok)
bad_config_dialog.setIcon(QMessageBox.Critical) bad_config_dialog.setIcon(QMessageBox.Icon.Critical)
reset_choice = bad_config_dialog.exec_() reset_choice = bad_config_dialog.exec()
return reset_choice == QMessageBox.Ok return reset_choice == QMessageBox.StandardButton.Ok
def main(): def main():
...@@ -95,7 +83,7 @@ def main(): ...@@ -95,7 +83,7 @@ def main():
try: try:
config.validate_config() config.validate_config()
config.apply_config(wnd) config.apply_config(wnd)
except (BadConfigError, ValueError) as e: except (BadConfigError, ValueError):
do_reset = check_if_user_want_to_reset_config() do_reset = check_if_user_want_to_reset_config()
if do_reset: if do_reset:
try: try:
...@@ -104,7 +92,7 @@ def main(): ...@@ -104,7 +92,7 @@ def main():
QMessageBox.critical(None, 'Cannot reset config', QMessageBox.critical(None, 'Cannot reset config',
'Config file cannot be reset. Please ensure ' 'Config file cannot be reset. Please ensure '
'that it is not opened in another program.', 'that it is not opened in another program.',
QMessageBox.Close) QMessageBox.StandardButton.Close)
sys.exit(1) sys.exit(1)
elif do_reset is not None: elif do_reset is not None:
sys.exit(1) sys.exit(1)
...@@ -112,7 +100,7 @@ def main(): ...@@ -112,7 +100,7 @@ def main():
resize_windows(wnd) resize_windows(wnd)
wnd.show() wnd.show()
sys.exit(app.exec_()) sys.exit(app.exec())
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -5,7 +5,8 @@ import traceback ...@@ -5,7 +5,8 @@ import traceback
from pathlib import Path from pathlib import Path
from typing import Union, List, Optional from typing import Union, List, Optional
from PySide2 import QtCore, QtWidgets from PySide6.QtCore import Qt
from PySide6 import QtCore, QtWidgets
from sohstationviewer.conf import constants from sohstationviewer.conf import constants
from sohstationviewer.controller.util import display_tracking_info from sohstationviewer.controller.util import display_tracking_info
...@@ -84,7 +85,7 @@ class DataLoaderWorker(QtCore.QObject): ...@@ -84,7 +85,7 @@ class DataLoaderWorker(QtCore.QObject):
# its unpause slot to the loader's unpause signal # its unpause slot to the loader's unpause signal
data_object = object_type.get_empty_instance() data_object = object_type.get_empty_instance()
self.button_chosen.connect(data_object.receive_pause_response, self.button_chosen.connect(data_object.receive_pause_response,
type=QtCore.Qt.DirectConnection) type=Qt.ConnectionType.DirectConnection)
data_object.__init__( data_object.__init__(
self.data_type, self.tracking_box, self.data_type, self.tracking_box,
self.is_multiplex, self.list_of_dir, self.is_multiplex, self.list_of_dir,
...@@ -119,7 +120,7 @@ class DataLoaderWorker(QtCore.QObject): ...@@ -119,7 +120,7 @@ class DataLoaderWorker(QtCore.QObject):
self.process_failed = True self.process_failed = True
self.failed.emit() self.failed.emit()
else: else:
if data_object.selected_key is None: if data_object.selected_data_set_id is None:
self.process_failed = True self.process_failed = True
self.end_msg = ("No data was found. Please check the selected " self.end_msg = ("No data was found. Please check the selected "
"time range and channel list.") "time range and channel list.")
......
## Log data: ## Log data:
info from log channels, soh messages, text file in dict: info from log channels, soh messages, text file in dict:
{'TEXT': [str,], key:{chan_id: [str,],},} {'TEXT': [str,], data_set_id:{chan_id: [str,],},}
In which 'TEXT': is the chan_id given by sohview for text only files which have In which 'TEXT': is the chan_id given by sohview for text only files which have
no station or channel associate with it. no station or channel associate with it.
Note: log_data for RT130's dataset has only one channel: SOH Note: log_data for RT130's dataset has only one channel: SOH
## data_dict: ## data_dict:
{set_key: { {data_set_id: {
chan_id (str): { chan_id (str): {
'file_path' (str): path of file to keep track of file changes in MSeedReader 'file_path' (str): path of file to keep track of file changes in MSeedReader
'chanID' (str): name of channel 'chanID' (str): name of channel
...@@ -35,10 +35,13 @@ soh channels are plotted in PlottingWidget and waveform channel are plotted in W ...@@ -35,10 +35,13 @@ soh channels are plotted in PlottingWidget and waveform channel are plotted in W
tps_data created in TimePoserSquareWidget only and apply for waveform_data only tps_data created in TimePoserSquareWidget only and apply for waveform_data only
## tps_data: data that aren't separated to traces ## tps_data: data that aren't separated to traces
{set_key - str or (str, str): { {data_set_id - str or (str, str): {
chan_id - str: { chan_id - str: {
times: np.array, times: np.array,
data: np.array, data: np.array,
} }
} }
} }
\ No newline at end of file
## soh_messages: SOH log messages in Search Messages Dialog
{'TEXT': [str,], data_set_id:{chan_id: [str,],},}
\ No newline at end of file