Skip to content
Snippets Groups Projects
Commit 1f98d9db authored by Kien Le's avatar Kien Le
Browse files

Documentation and refactor

parent bb04f9e2
No related branches found
No related tags found
No related merge requests found
import math
import sys
from pathlib import Path
from typing import List
import numpy as np
from matplotlib import pyplot as plt
from typing import List, Optional
from sohstationviewer.controller.util import displayTrackingInfo
from sohstationviewer.model.gps_point import GPSPoint
from sohstationviewer.model.mseed.mseed import MSeed
from PySide2 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg as Canvas
)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
from matplotlib.figure import Figure
from matplotlib.axes import Axes
class GPSWidget(QtWidgets.QWidget):
def __init__(self, parent, tracking_box):
def __init__(self, parent: QtWidgets.QWidget,
tracking_box: QtWidgets.QTextBrowser):
super().__init__(parent)
self.tracking_box = tracking_box
self.gps_points: List[GPSPoint] = None
self.gps_points: Optional[List[GPSPoint]] = None
self.fig = Figure(figsize=(6, 6), dpi=100)
self.canvas = Canvas(self.fig)
......@@ -30,7 +26,9 @@ class GPSWidget(QtWidgets.QWidget):
self.ax: Axes = self.fig.add_axes((0, 0, 1, 1))
self.ax.set_facecolor("dimgray")
# Force the plot to be square.
self.ax.set_box_aspect(1)
# Remove all traces of the axes, leaving only the plot.
self.ax.set_yticks([])
self.ax.set_xticks([])
self.ax.spines['right'].set_visible(False)
......@@ -40,6 +38,11 @@ class GPSWidget(QtWidgets.QWidget):
@QtCore.Slot()
def plot_gps(self):
"""
Plot the GPS points onto the canvas. Display the latitude and longitude
range in meters and adjust the x and y limits of the plot so that the
axis is square.
"""
all_latitudes = [point.latitude for point in self.gps_points]
all_longitudes = [point.longitude for point in self.gps_points]
max_latitude = max(all_latitudes)
......@@ -47,26 +50,24 @@ class GPSWidget(QtWidgets.QWidget):
max_longitude = max(all_longitudes)
min_longitude = min(all_longitudes)
latitude_range = max_latitude - min_latitude
longitude_range = max_longitude - min_longitude
latitude_range = convert_latitude_degree_to_meter(latitude_range)
# Use the average latitude as the latitude in the longitude conversion
# to find the average range of longitude.
latitude_range = convert_latitude_degree_to_meter(
max_latitude - min_latitude
)
# qpeek uses the average latitude in this conversion, so we copy it.
longitude_range = convert_longitude_degree_to_meter(
longitude_range, (max_latitude + min_latitude) / 2
max_longitude - min_longitude,
(max_latitude + min_latitude) / 2
)
self.ax.plot(all_longitudes, all_latitudes, 'ws', markersize=4,
markeredgecolor='black', picker=True, pickradius=4)
range_text = (
f'Lat range: {latitude_range:.2f}m '
f'Long range: {longitude_range:.2f}m'
)
self.ax.text(
0.01, 0.96, range_text, color='white', size=10,
transform=self.ax.transAxes
)
range_text = (f'Lat range: {latitude_range:.2f}m '
f'Long range: {longitude_range:.2f}m')
self.ax.text(0.01, 0.96, range_text, color='white', size=10,
transform=self.ax.transAxes
)
# Stretch the shorter axis so that it is as long as the longer axis.
latitude_range = max_latitude - min_latitude
longitude_range = max_longitude - min_longitude
if latitude_range > longitude_range:
......@@ -86,35 +87,37 @@ class GPSWidget(QtWidgets.QWidget):
displayTrackingInfo(self.tracking_box, msg)
def on_pick_event(self, event):
artist = event.artist
if isinstance(artist, plt.Line2D):
# index of the clicked point on the plot
click_plot_index = event.ind[0]
picked_point = self.gps_points[click_plot_index]
lat_dir = 'N' if picked_point.latitude > 0 else 'S'
long_dir = 'E' if picked_point.longitude > 0 else 'W'
lat = abs(picked_point.latitude)
long = abs(picked_point.longitude)
meta_separator = ' ' * 22
loc_separator = ' ' * 10
msg = (
f'Mark: {picked_point.last_timemark}{meta_separator}'
f'Fix: {picked_point.fix_type}{meta_separator}'
f'Sats: {picked_point.num_satellite_used}<br>'
f'Lat: {lat_dir}{lat:.6f}{loc_separator}'
f'Long: {long_dir}{long:.6f}{loc_separator}'
f'Elev: {picked_point.height}{picked_point.height_unit}'
)
displayTrackingInfo(self.tracking_box, msg)
"""
On a GPS point being picked, display the data of that point onto the
tracking box.
:param event: the pick event
"""
# index of the clicked point on the plot
click_plot_index = event.ind[0]
picked_point = self.gps_points[click_plot_index]
lat_dir = 'N' if picked_point.latitude > 0 else 'S'
long_dir = 'E' if picked_point.longitude > 0 else 'W'
meta_separator = '&nbsp;' * 22
loc_separator = '&nbsp;' * 10
msg = (
f'Mark: {picked_point.last_timemark}{meta_separator}'
f'Fix: {picked_point.fix_type}{meta_separator}'
f'Sats: {picked_point.num_satellite_used}<br>'
f'Lat: {lat_dir}{abs(picked_point.latitude):.6f}{loc_separator}'
f'Long: {long_dir}{abs(picked_point.longitude):.6f}{loc_separator}'
f'Elev: {picked_point.height}{picked_point.height_unit}'
)
displayTrackingInfo(self.tracking_box, msg)
class GPSDialog(QtWidgets.QWidget):
def __init__(self, parent=None):
def __init__(self, parent: QtWidgets.QWidget = None):
super().__init__()
self.parent = parent
self.data_path = None
self.data_path: Path = None
self.info_text_browser = QtWidgets.QTextBrowser(self)
self.plotting_widget = GPSWidget(self, self.info_text_browser)
......@@ -126,6 +129,9 @@ class GPSDialog(QtWidgets.QWidget):
self.setup_ui()
def setup_ui(self):
"""
Set up the user interface of the dialog.
"""
# The height of the dialog is chosen so that the GPS plot is flush with
# the edges of the dialog.
dialog_height = 518
......@@ -184,6 +190,15 @@ class GPSDialog(QtWidgets.QWidget):
if not point.is_bad_point()]
def export_gps_points(self):
"""
Export the data of the GPS points to a file. The file will be in the
same directory as the data folder.
The first line in the export file contains information about the data
set. Each subsequent line has the form
<YYYY-MM-DD HH:MM:SS> <fix type> <no. sats. used> <latitude:.6f> <longitude:.6f> <height:.6f> # noqa
and is tab-separated.
"""
folder_name = self.data_path.name
outside_folder = self.data_path.parent
with open(outside_folder / f'{folder_name}.gps.dat', 'w+') as outfile:
......@@ -210,6 +225,12 @@ EQUATORIAL_CIRCUMFERENCE = 40075017
def convert_latitude_degree_to_meter(lat: float) -> float:
"""
Convert the given latitude from degree to meter.
:param lat: latitude given in degree
:return: the given latitude converted to meter
"""
# A whole circumference is 360 degrees, so we can get the length of one
# degree by dividing the circumference by 360.
lat_degree_length_in_meter = POLAR_CIRCUMFERENCE / 360
......@@ -217,11 +238,18 @@ def convert_latitude_degree_to_meter(lat: float) -> float:
def convert_longitude_degree_to_meter(long: float, lat: float) -> float:
"""
Convert the given longitude from degree to meter. Need to adjust for
latitude because the length of a longitude degree changes with the
latitude.
:param long: longitude given in degree
:param lat: the latitude to adjust for
:return: the given longitude converted to meter
"""
# A whole circumference is 360 degrees, so we can get the length of one
# degree by dividing the circumference by 360.
long_degree_length_in_meter = EQUATORIAL_CIRCUMFERENCE / 360
# The length of a longitude degree varies with the latitude, being greatest
# around the equator and approaching 0 near to the poles.
adjustment_for_latitude = math.cos(math.radians(lat))
return long * long_degree_length_in_meter * adjustment_for_latitude
......@@ -232,8 +260,8 @@ if __name__ == '__main__':
os.chdir('/Users/kle/PycharmProjects/sohstationviewer')
app = QtWidgets.QApplication(sys.argv)
# data_path = '/Users/kle/PycharmProjects/sohstationviewer/tests/test_data/Q330-sample'
data_path = '/Users/kle/Documents/SOHView data/Q330/Q330_5281.sdr'
data_path = '/Users/kle/PycharmProjects/sohstationviewer/tests/test_data/Q330-sample'
# data_path = '/Users/kle/Documents/SOHView data/Q330/Q330_5281.sdr'
data = MSeed(QtWidgets.QTextBrowser(), data_path)
wnd = GPSDialog()
......@@ -242,6 +270,3 @@ if __name__ == '__main__':
wnd.show()
sys.exit(app.exec_())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment