diff --git a/sohstationviewer/view/main_window.py b/sohstationviewer/view/main_window.py index 3ed9e513fd5e6ce632763298b051b57d03097230..6a4de80696f266603ca21a672184a394bb479064 100755 --- a/sohstationviewer/view/main_window.py +++ b/sohstationviewer/view/main_window.py @@ -86,7 +86,7 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow): selected_rt130_paths: list of data paths for selected rt130 to pass to data_loader.init_loader for processing """ - self.selected_rt130_paths: List[str] = [] + self.selected_rt130_paths: List[Path] = [] """ rt130_log_files: list of log files to be read """ @@ -518,6 +518,9 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow): for item in self.open_files_list.selectedItems(): log_abspath = root_dir.joinpath(item.file_path) self.rt130_log_files.append(log_abspath) + if not self.rt130_log_files: + msg = "No RT130 log file were selected." + raise Exception(msg) # Log files can only come from programs that work with RT130 data. self.data_type = 'RT130' self.is_multiplex = False @@ -617,6 +620,10 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow): "Loading started", LogType.INFO) self.clear_plots() + self.gps_dialog.clear_plot() + self.gps_dialog.set_data_path('') + self.gps_dialog.gps_points = [] + start_tm_str = self.time_from_date_edit.date().toString( QtCore.Qt.DateFormat.ISODate ) @@ -723,11 +730,6 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow): self.start_tm = datetime.strptime(start_tm_str, TM_FORMAT).timestamp() self.end_tm = datetime.strptime(end_tm_str, TM_FORMAT).timestamp() - self.gps_dialog.clear_plot() - self.gps_dialog.data_path = self.curr_dir_line_edit.text() - self.gps_dialog.set_export_directory(self.curr_dir_line_edit.text()) - self.gps_dialog.gps_points = [] - self.data_loader.init_loader( self.data_type, self.tracking_info_text_browser, @@ -839,6 +841,27 @@ class MainWindow(QtWidgets.QMainWindow, UIMainWindow): self.processing_log.append(log_message) log_message = ('Cannot get GPS data.', LogType.WARNING) self.processing_log.append(log_message) + if self.rt130_log_files: + data_path = self.rt130_log_files[0] + elif self.selected_rt130_paths: + # The selected RT130 paths looks something like + # <Data directory>/<Data folder>/<Day 1>/<Station>, + # <Data directory>/<Data folder>/<Day 2>/<Station>, ... + # We want to grab the data folder, because it is the common + # point of the paths. + # Note: there can be more than one data folder. However, we + # only need one. + data_path = self.selected_rt130_paths[0].parent.parent + elif self.list_of_dir: + dir_path = self.list_of_dir[0] + if dir_path.name == 'data' or dir_path.name == 'sdata': + # When reading inside a Baler data set with the data card + # option enabled, the data folder is appended with either + # data or sdata. + data_path = dir_path.parent + else: + data_path = dir_path + self.gps_dialog.set_data_path(str(data_path)) data_set_info = extract_data_set_info(data_obj, self.date_format) for info_name, info in data_set_info.items(): diff --git a/sohstationviewer/view/plotting/gps_plot/extract_gps_data.py b/sohstationviewer/view/plotting/gps_plot/extract_gps_data.py index 52f82d173e49b723d1b3fa4dbfd7788170c58a07..ff8380ed6f0eb89707b6bfa634c375383f7fbe54 100644 --- a/sohstationviewer/view/plotting/gps_plot/extract_gps_data.py +++ b/sohstationviewer/view/plotting/gps_plot/extract_gps_data.py @@ -22,6 +22,8 @@ def extract_gps_data_q330(data_obj: MSeed) -> List[GPSPoint]: for station in data_obj.log_data: if station == 'TEXT': continue + if 'LOG' not in data_obj.log_data[station]: + continue # Q330 log data is composed of a list of string, so we combine them # into one big string for ease of processing. log_str = functools.reduce( diff --git a/sohstationviewer/view/plotting/gps_plot/gps_dialog.py b/sohstationviewer/view/plotting/gps_plot/gps_dialog.py index aad2ee212dd0bed58d963adf8b3687bdcd1e5607..ffe1731ccf43f3004d8e90aa968883e81d7f6500 100644 --- a/sohstationviewer/view/plotting/gps_plot/gps_dialog.py +++ b/sohstationviewer/view/plotting/gps_plot/gps_dialog.py @@ -1,11 +1,11 @@ import math -import sys -import os import traceback from pathlib import Path from typing import List, Optional, Literal, Iterable, Any from PySide6 import QtWidgets, QtCore +from PySide6.QtCore import Qt +from PySide6.QtWidgets import QWidget, QLineEdit, QLabel, QHBoxLayout from matplotlib.axes import Axes from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas from matplotlib.figure import Figure @@ -13,10 +13,44 @@ from matplotlib.text import Text from sohstationviewer.controller.util import display_tracking_info from sohstationviewer.view.plotting.gps_plot.gps_point import GPSPoint -from sohstationviewer.model.mseed_data.mseed import MSeed from sohstationviewer.view.util.enums import LogType +class SuffixedLineEdit(QWidget): + """ + A one-line text editor that contains a default suffix. + """ + def __init__(self, suffix: str, parent: Optional[QWidget] = None): + super().__init__(parent) + self.editor = QLineEdit(self) + self.editor.setContentsMargins(0, 0, 0, 0) + + self.suffix = QLabel(suffix, self) + self.setup_ui() + + def setup_ui(self): + layout = QHBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(0) + self.setLayout(layout) + layout.addWidget(self.editor, 1) + layout.addWidget(self.suffix) + + def set_text(self, text: str): + """ + Set the content of this editor. + :param text: the new content of this editor + """ + self.editor.setText(text) + + def text(self) -> str: + """ + Return the content of this editor. + :return: the content of this editor with the suffix attached + """ + return self.editor.text() + self.suffix.text() + + class GPSWidget(QtWidgets.QWidget): """ Widget that contains the GPS plot. @@ -29,6 +63,9 @@ class GPSWidget(QtWidgets.QWidget): # It would be a waste of time to plot points that have the same # coordinates (i.e. the same latitude and longitude) so we only plot # one point for each coordinate. + # We use a list instead of a set because matplotlib's pick event only + # provides the index of a point being clicked, and set doesn't support + # indexing. self.unique_gps_points: Optional[List[GPSPoint]] = None self.fig = Figure(figsize=(6, 6), dpi=100, facecolor='#ECECEC') @@ -190,13 +227,20 @@ class GPSDialog(QtWidgets.QWidget): super().__init__() self.parent = parent - self.data_path: Optional[Path, str] = None + self.export_file_extension = '.gps.dat' + + self.data_path: Optional[Path] = None # The directory the GPS will be exported to. By default, this will be # the folder that contains the data set. - self.export_path: Path = Path.home() + self.export_dir: Path = Path('') self.export_dir_button = QtWidgets.QPushButton("Export Directory") - self.export_dir_textbox = QtWidgets.QLineEdit(os.path.expanduser('~')) + self.export_dir_textbox = QtWidgets.QLineEdit() + + self.export_file_name_label = QtWidgets.QLabel("Export File Name:") + self.export_file_name_textbox = SuffixedLineEdit( + self.export_file_extension + ) self.info_text_browser = QtWidgets.QTextBrowser(self) self.plotting_widget = GPSWidget(self, self.info_text_browser) @@ -211,10 +255,9 @@ class GPSDialog(QtWidgets.QWidget): """ Set up the user interface of the dialog. """ - # The height of the dialog is chosen so that the GPS plot is flush with + # The size of the dialog is chosen so that the GPS plot is flush with # the edges of the dialog. - dialog_height = 602 - self.setGeometry(300, 300, 490, dialog_height) + self.setGeometry(300, 300, 449, 579) self.setWindowTitle("GPS Plot") main_layout = QtWidgets.QVBoxLayout() @@ -222,15 +265,20 @@ class GPSDialog(QtWidgets.QWidget): main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) - export_dir_layout = QtWidgets.QHBoxLayout() - export_dir_layout.addWidget(self.export_dir_button) - export_dir_layout.addWidget(self.export_dir_textbox) - # self.export_dir_textbox.setReadOnly(True) - self.export_dir_textbox.setCursor(QtCore.Qt.CursorShape.IBeamCursor) - export_dir_layout.setContentsMargins(5, 7, 5, 0) - export_dir_layout.setStretch(1, 3) - export_dir_layout.setSpacing(5) - main_layout.addLayout(export_dir_layout) + export_layout = QtWidgets.QGridLayout() + export_layout.addWidget(self.export_dir_button, 0, 0) + export_layout.addWidget(self.export_dir_textbox, 0, 1) + self.export_dir_textbox.setReadOnly(True) + export_layout.setSpacing(5) + + export_layout.addWidget(self.export_file_name_label, 1, 0, + Qt.AlignmentFlag.AlignCenter) + self.export_file_name_label.setContentsMargins(4, 0, 0, 0) + export_layout.addWidget(self.export_file_name_textbox, 1, 1) + export_layout.setContentsMargins(5, 0, 5, 0) + export_layout.setSpacing(5) + + main_layout.addLayout(export_layout) main_layout.addWidget(self.plotting_widget.canvas) @@ -330,13 +378,25 @@ class GPSDialog(QtWidgets.QWidget): new_path = fd.selectedFiles()[0] self.set_export_directory(new_path) + def set_data_path(self, data_path: str): + """ + Set the path to the data. Because the initial export path is dependent + on the data path, it will be set as well. + :param data_path: the path to the data as a string. Can be either a + directory or a file. + """ + data_path = Path(data_path) + self.data_path = data_path + self.export_file_name_textbox.set_text(str(data_path.name)) + self.set_export_directory(str(data_path.parent)) + def set_export_directory(self, dir_path: str) -> None: """ Set the GPS data export directory to dir_path. :param dir_path: the path to set the data export directory to """ self.export_dir_textbox.setText(dir_path) - self.export_path = Path(dir_path) + self.export_dir = Path(dir_path) def export_gps_points(self) -> None: """ @@ -353,15 +413,12 @@ class GPSDialog(QtWidgets.QWidget): msg = 'There is no GPS data to export.' display_tracking_info(self.info_text_browser, msg, LogType.ERROR) return - try: - folder_name = self.data_path.name - except AttributeError: - folder_name = self.data_path.split(os.sep)[-1] - export_file_path = self.export_path / f'{folder_name}.gps.dat' + export_file_name = self.export_file_name_textbox.text() + export_file_path = self.export_dir / export_file_name try: with open(export_file_path, 'w+') as outfile: - outfile.write(f'# GPS data points for {folder_name}\n') + outfile.write(f'# GPS data points for {self.data_path.name}\n') for point in self.gps_points: if point.is_bad_point(): continue @@ -418,20 +475,3 @@ def convert_longitude_degree_to_meter(long: float, lat: float) -> float: long_degree_length_in_meter = EQUATORIAL_CIRCUMFERENCE / 360 adjustment_for_latitude = math.cos(math.radians(lat)) return long * long_degree_length_in_meter * adjustment_for_latitude - - -if __name__ == '__main__': - - os.chdir('/') - app = QtWidgets.QApplication(sys.argv) - - data_path = '/test_data/Q330-sample' # noqa: E501 - # data_path = '/Users/kle/Documents/SOHView data/Q330/Q330_5281.sdr' - data = MSeed(QtWidgets.QTextBrowser(), data_path) - - wnd = GPSDialog() - wnd.gps_points = data.gps_points - wnd.data_path = Path(data_path) - wnd.show() - - sys.exit(app.exec())