Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to display a secondary axis in SideView. #980

Merged
merged 3 commits into from
May 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions mslib/msui/_tests/test_suffix.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"""

import sys
from PyQt5 import QtWidgets, QtTest, QtCore
from PyQt5 import QtWidgets, QtTest
import mslib.msui.sideview as tv


Expand All @@ -48,12 +48,8 @@ def teardown(self):
QtWidgets.QApplication.processEvents()

def test_suffixchange(self):
cbView = self.window.cbVerticalAxis.view()
suffix = [' hpa', ' km', ' hft']
suffix = [' hPa', ' km', ' hft']
for i in range(len(suffix)):
index = cbView.model().index(i, 0)
cbView.scrollTo(index)
item_react = cbView.visualRect(index)
QtTest.QTest.mouseClick(cbView.viewport(), QtCore.Qt.LeftButton, QtCore.Qt.NoModifier, item_react.center())
self.window.cbVerticalAxis.setCurrentIndex(i)
QtWidgets.QApplication.processEvents()
assert self.window.sbPtop.suffix() == suffix[i]
139 changes: 70 additions & 69 deletions mslib/msui/mpl_qtwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ def __init__(self, model=None, settings=None, numlabels=None):
# Default settings.
self.settings_dict = {"vertical_extent": (1050, 180),
"vertical_axis": "pressure",
"secondary_axis": "no secondary axis",
"flightlevels": [],
"draw_flightlevels": True,
"draw_flighttrack": True,
Expand All @@ -501,15 +502,20 @@ def __init__(self, model=None, settings=None, numlabels=None):
self.settings_dict.update(settings)

# Setup the plot.
self.p_bot = self.settings_dict["vertical_extent"][0] * 100
self.p_top = self.settings_dict["vertical_extent"][1] * 100
self.update_vertical_extent_from_settings(init=True)

self.numlabels = numlabels
self.ax2 = self.ax.twinx()
self.ax.patch.set_facecolor("None")
self.ax2.patch.set_facecolor("None")
# Main axes instance of mplwidget has zorder 99.
self.imgax = self.fig.add_axes(
self.ax.get_position(), frameon=True, xticks=[], yticks=[], label="imgax", zorder=0)
self.setup_side_view()
# Draw a number of flight level lines.
self.flightlevels = []
self.fl_label_list = []
self.draw_flight_levels()
self.imgax = None
self.image = None
self.ceiling_alt = []
# If a waypoints model has been passed, create an interactor on it.
Expand Down Expand Up @@ -538,12 +544,13 @@ def set_waypoints_model(self, model):
redraw_xaxis=self.redraw_xaxis, clear_figure=self.clear_figure
)

def redraw_yaxis(self):
""" Redraws the y-axis on map after setting the values from sideview options dialog box"""

self.checknconvert()
vaxis = self.settings_dict["vertical_axis"]
if vaxis == "pressure":
def _determine_ticks_labels(self, typ):
if typ == "no secondary axis":
major_ticks = []
minor_ticks = []
labels = []
ylabel = ""
elif typ == "pressure":
# Compute the position of major and minor ticks. Major ticks are labelled.
major_ticks = self._pres_maj[(self._pres_maj <= self.p_bot) & (self._pres_maj >= self.p_top)]
minor_ticks = self._pres_min[(self._pres_min <= self.p_bot) & (self._pres_min >= self.p_top)]
Expand All @@ -553,8 +560,8 @@ def redraw_yaxis(self):
labels = ["" if x.split(".")[-1][0] in "975" else x for x in labels]
elif len(labels) > 10:
labels = ["" if x.split(".")[-1][0] in "9" else x for x in labels]
self.ax.set_ylabel("pressure (hPa)")
elif vaxis == "pressure altitude":
ylabel = "pressure (hPa)"
elif typ == "pressure altitude":
bot_km = thermolib.pressure2flightlevel(self.p_bot) * 0.03048
top_km = thermolib.pressure2flightlevel(self.p_top) * 0.03048
ma_dist, mi_dist = 4, 1.0
Expand All @@ -567,8 +574,8 @@ def redraw_yaxis(self):
major_ticks = thermolib.flightlevel2pressure_a(major_heights / 0.03048)
minor_ticks = thermolib.flightlevel2pressure_a(minor_heights / 0.03048)
labels = major_heights
self.ax.set_ylabel("pressure altitude (km)")
elif vaxis == "flight level":
ylabel = "pressure altitude (km)"
elif typ == "flight level":
bot_km = thermolib.pressure2flightlevel(self.p_bot) * 0.03048
top_km = thermolib.pressure2flightlevel(self.p_top) * 0.03048
ma_dist, mi_dist = 50, 10
Expand All @@ -581,36 +588,49 @@ def redraw_yaxis(self):
major_ticks = thermolib.flightlevel2pressure_a(major_fl)
minor_ticks = thermolib.flightlevel2pressure_a(minor_fl)
labels = major_fl
self.ax.set_ylabel("flight level (hft)")
ylabel = "flight level (hft)"
else:
raise RuntimeError(f"Unsupported vertical axis type: '{vaxis}'")
raise RuntimeError(f"Unsupported vertical axis type: '{typ}'")
return ylabel, major_ticks, minor_ticks, labels

def redraw_yaxis(self):
""" Redraws the y-axis on map after setting the values from sideview options dialog box"""

vaxis = self.settings_dict["vertical_axis"]
vaxis2 = self.settings_dict["secondary_axis"]

for ax, typ in zip((self.ax, self.ax2), (vaxis, vaxis2)):
ylabel, major_ticks, minor_ticks, labels = self._determine_ticks_labels(typ)

# Draw ticks and tick labels.
self.ax.set_yticks(minor_ticks, minor=True)
self.ax.set_yticks(major_ticks, minor=False)
self.ax.set_yticklabels([], minor=True, fontsize=10)
self.ax.set_yticklabels(labels, minor=False, fontsize=10)
self.ax.set_ylim(self.p_bot, self.p_top)
ax.set_ylabel(ylabel)
ax.set_yticks(minor_ticks, minor=True)
ax.set_yticks(major_ticks, minor=False)
ax.set_yticklabels([], minor=True, fontsize=10)
ax.set_yticklabels(labels, minor=False, fontsize=10)
ax.set_ylim(self.p_bot, self.p_top)

if vaxis2 == "no secondary axis":
self.fig.subplots_adjust(left=0.08, right=0.96, top=0.9, bottom=0.14)
self.imgax.set_position(self.ax.get_position())
else:
self.fig.subplots_adjust(left=0.08, right=0.92, top=0.9, bottom=0.14)
self.imgax.set_position(self.ax.get_position())

def setup_side_view(self):
"""Set up a vertical section view.

Vertical cross section code (log-p axis etc.) taken from
mss_batch_production/visualisation/mpl_vsec.py.
"""
self.checknconvert()

ax = self.ax
self.fig.subplots_adjust(left=0.08, right=0.96, top=0.9, bottom=0.14)

ax.set_title("vertical flight profile", horizontalalignment="left", x=0)
ax.set_yscale("log")
self.ax.set_title("vertical flight profile", horizontalalignment="left", x=0)
self.ax.grid(b=True)
self.ax.set_xlabel("lat/lon")

# Set axis limits and draw grid for major ticks.
ax.set_ylim(self.p_bot, self.p_top)
ax.grid(b=True)
for ax in (self.ax, self.ax2):
ax.set_yscale("log")
ax.set_ylim(self.p_bot, self.p_top)

ax.set_xlabel("lat/lon")
self.redraw_yaxis()

def clear_figure(self):
Expand Down Expand Up @@ -674,32 +694,9 @@ def redraw_xaxis(self, lats, lons, times):

self.draw()

def set_vertical_extent(self, pbot, ptop):
"""Set the vertical extent of the view to the specified pressure
values (hPa) and redraw the plot.
"""
self.checknconvert()
changed = False
if self.p_bot != pbot * 100:
self.p_bot = pbot * 100
changed = True
if self.p_top != ptop * 100:
self.p_top = ptop * 100
changed = True
if changed:
if self.image is not None:
self.image.remove()
self.image = None
self.setup_side_view()
self.waypoints_interactor.redraw_figure()
else:
self.redraw_yaxis()

def get_vertical_extent(self):
"""Returns the bottom and top pressure (hPa) of the plot.
"""
self.checknconvert()

return (self.p_bot // 100), (self.p_top // 100)

def draw_flight_levels(self):
Expand Down Expand Up @@ -756,13 +753,13 @@ def set_settings(self, settings):
self.settings_dict.update(settings)
settings = self.settings_dict
self.set_flight_levels(settings["flightlevels"])
self.set_vertical_extent(*settings["vertical_extent"])
self.set_flight_levels_visible(settings["draw_flightlevels"])
self.update_ceiling(
settings["draw_ceiling"] and (
self.waypoints_model is not None and
self.waypoints_model.performance_settings["visible"]),
settings["colour_ceiling"])
self.update_vertical_extent_from_settings()

if self.waypoints_interactor is not None:
self.waypoints_interactor.set_vertices_visible(
Expand Down Expand Up @@ -815,19 +812,6 @@ def draw_image(self, img):
logging.debug("plotting vertical section image..")
ix, iy = img.size
logging.debug(" image size is %dx%d px, format is '%s'", ix, iy, img.format)
# Test if the image axes exist. If not, create them.
if self.imgax is None:
# Disable old white figure background so that the new underlying
# axes become visible.
self.ax.patch.set_facecolor("None")
# self.mpl.canvas.ax.patch.set_alpha(0.5)

# Add new axes to the plot (imshow doesn't work with logarithmic axes).
ax_bbox = self.ax.get_position()
# Main axes instance of mplwidget has zorder 99.
self.imgax = self.fig.add_axes(ax_bbox, frameon=True,
xticks=[], yticks=[],
label="ax2", zorder=0)

# If an image is currently displayed, remove it from the plot.
if self.image is not None:
Expand All @@ -841,16 +825,33 @@ def draw_image(self, img):
self.draw()
logging.debug("done.")

def checknconvert(self):
def update_vertical_extent_from_settings(self, init=False):
""" Checks for current units of axis and convert the upper and lower limit
to pa(pascals) for the internal computation by code """

if not init:
p_bot_old = self.p_bot
p_top_old = self.p_top

if self.settings_dict["vertical_axis"] == "pressure altitude":
self.p_bot = thermolib.flightlevel2pressure(self.settings_dict["vertical_extent"][0] * 32.80)
self.p_top = thermolib.flightlevel2pressure(self.settings_dict["vertical_extent"][1] * 32.80)
elif self.settings_dict["vertical_axis"] == "flight level":
self.p_bot = thermolib.flightlevel2pressure(self.settings_dict["vertical_extent"][0])
self.p_top = thermolib.flightlevel2pressure(self.settings_dict["vertical_extent"][1])
else:
self.p_bot = self.settings_dict["vertical_extent"][0] * 100
self.p_top = self.settings_dict["vertical_extent"][1] * 100

if not init:
if (p_bot_old != self.p_bot) or (p_top_old != self.p_top):
if self.image is not None:
self.image.remove()
self.image = None
self.setup_side_view()
self.waypoints_interactor.redraw_figure()
else:
self.redraw_yaxis()


class MplSideViewWidget(MplNavBarWidget):
Expand Down
58 changes: 47 additions & 11 deletions mslib/msui/qt5/ui_sideview_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

# Form implementation generated from reading ui file 'mslib/msui/ui/ui_sideview_options.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
# Created by: PyQt5 UI code generator 5.12.3
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_SideViewOptionsDialog(object):
def setupUi(self, SideViewOptionsDialog):
SideViewOptionsDialog.setObjectName("SideViewOptionsDialog")
SideViewOptionsDialog.resize(489, 622)
SideViewOptionsDialog.resize(489, 647)
self.verticalLayout_4 = QtWidgets.QVBoxLayout(SideViewOptionsDialog)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.groupBox = QtWidgets.QGroupBox(SideViewOptionsDialog)
Expand Down Expand Up @@ -51,11 +53,23 @@ def setupUi(self, SideViewOptionsDialog):
self.sbPtop.setObjectName("sbPtop")
self.horizontalLayout.addWidget(self.sbPtop)
self.verticalLayout_6.addLayout(self.horizontalLayout)
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.label_4 = QtWidgets.QLabel(self.groupBox)
self.label_4.setObjectName("label_4")
self.horizontalLayout_7.addWidget(self.label_4)
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.label_5 = QtWidgets.QLabel(self.groupBox)
self.label_5.setObjectName("label_5")
self.gridLayout.addWidget(self.label_5, 1, 0, 1, 1)
self.cbVerticalAxis2 = QtWidgets.QComboBox(self.groupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.cbVerticalAxis2.sizePolicy().hasHeightForWidth())
self.cbVerticalAxis2.setSizePolicy(sizePolicy)
self.cbVerticalAxis2.setObjectName("cbVerticalAxis2")
self.cbVerticalAxis2.addItem("")
self.cbVerticalAxis2.addItem("")
self.cbVerticalAxis2.addItem("")
self.cbVerticalAxis2.addItem("")
self.gridLayout.addWidget(self.cbVerticalAxis2, 1, 1, 1, 1)
self.cbVerticalAxis = QtWidgets.QComboBox(self.groupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
Expand All @@ -66,8 +80,11 @@ def setupUi(self, SideViewOptionsDialog):
self.cbVerticalAxis.addItem("")
self.cbVerticalAxis.addItem("")
self.cbVerticalAxis.addItem("")
self.horizontalLayout_7.addWidget(self.cbVerticalAxis)
self.verticalLayout_6.addLayout(self.horizontalLayout_7)
self.gridLayout.addWidget(self.cbVerticalAxis, 0, 1, 1, 1)
self.label_4 = QtWidgets.QLabel(self.groupBox)
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1)
self.verticalLayout_6.addLayout(self.gridLayout)
self.verticalLayout_4.addWidget(self.groupBox)
self.groupBox_2 = QtWidgets.QGroupBox(SideViewOptionsDialog)
font = QtGui.QFont()
Expand Down Expand Up @@ -203,6 +220,21 @@ def setupUi(self, SideViewOptionsDialog):
self.buttonBox.accepted.connect(SideViewOptionsDialog.accept)
self.buttonBox.rejected.connect(SideViewOptionsDialog.reject)
QtCore.QMetaObject.connectSlotsByName(SideViewOptionsDialog)
SideViewOptionsDialog.setTabOrder(self.sbPbot, self.sbPtop)
SideViewOptionsDialog.setTabOrder(self.sbPtop, self.cbVerticalAxis)
SideViewOptionsDialog.setTabOrder(self.cbVerticalAxis, self.cbVerticalAxis2)
SideViewOptionsDialog.setTabOrder(self.cbVerticalAxis2, self.cbDrawFlightLevels)
SideViewOptionsDialog.setTabOrder(self.cbDrawFlightLevels, self.tableWidget)
SideViewOptionsDialog.setTabOrder(self.tableWidget, self.btAdd)
SideViewOptionsDialog.setTabOrder(self.btAdd, self.btDelete)
SideViewOptionsDialog.setTabOrder(self.btDelete, self.cbDrawFlightTrack)
SideViewOptionsDialog.setTabOrder(self.cbDrawFlightTrack, self.btWaypointsColour)
SideViewOptionsDialog.setTabOrder(self.btWaypointsColour, self.btVerticesColour)
SideViewOptionsDialog.setTabOrder(self.btVerticesColour, self.cbFillFlightTrack)
SideViewOptionsDialog.setTabOrder(self.cbFillFlightTrack, self.btFillColour)
SideViewOptionsDialog.setTabOrder(self.btFillColour, self.cbLabelFlightTrack)
SideViewOptionsDialog.setTabOrder(self.cbLabelFlightTrack, self.cbDrawCeiling)
SideViewOptionsDialog.setTabOrder(self.cbDrawCeiling, self.btCeilingColour)

def retranslateUi(self, SideViewOptionsDialog):
_translate = QtCore.QCoreApplication.translate
Expand All @@ -212,10 +244,15 @@ def retranslateUi(self, SideViewOptionsDialog):
self.sbPbot.setSuffix(_translate("SideViewOptionsDialog", " hpa"))
self.label_3.setText(_translate("SideViewOptionsDialog", "to"))
self.sbPtop.setSuffix(_translate("SideViewOptionsDialog", " hpa"))
self.label_4.setText(_translate("SideViewOptionsDialog", "Vertical axis units:"))
self.label_5.setText(_translate("SideViewOptionsDialog", "Secondary axis units: "))
self.cbVerticalAxis2.setItemText(0, _translate("SideViewOptionsDialog", "no secondary axis"))
self.cbVerticalAxis2.setItemText(1, _translate("SideViewOptionsDialog", "pressure"))
self.cbVerticalAxis2.setItemText(2, _translate("SideViewOptionsDialog", "pressure altitude"))
self.cbVerticalAxis2.setItemText(3, _translate("SideViewOptionsDialog", "flight level"))
self.cbVerticalAxis.setItemText(0, _translate("SideViewOptionsDialog", "pressure"))
self.cbVerticalAxis.setItemText(1, _translate("SideViewOptionsDialog", "pressure altitude"))
self.cbVerticalAxis.setItemText(2, _translate("SideViewOptionsDialog", "flight level"))
self.label_4.setText(_translate("SideViewOptionsDialog", "Vertical axis units: "))
self.groupBox_2.setTitle(_translate("SideViewOptionsDialog", "Flight Levels"))
self.cbDrawFlightLevels.setText(_translate("SideViewOptionsDialog", "draw the following flight levels:"))
item = self.tableWidget.horizontalHeaderItem(0)
Expand All @@ -232,4 +269,3 @@ def retranslateUi(self, SideViewOptionsDialog):
self.groupBox_4.setTitle(_translate("SideViewOptionsDialog", "Performance"))
self.cbDrawCeiling.setText(_translate("SideViewOptionsDialog", "draw ceiling altitude"))
self.btCeilingColour.setText(_translate("SideViewOptionsDialog", "colour"))

Loading