Source code for sofia_redux.visualization.display.reference_window
import os
from typing import Any
from sofia_redux.visualization import log
from sofia_redux.visualization.display.text_view import TextView
try:
from PyQt6 import QtWidgets, QtGui, QtCore
from sofia_redux.visualization.display.ui import reference_data as rd
except ImportError: # pragma: no cover
HAS_PYQT6 = False
QtGui, QtCore = None, None
class QtWidgets:
class QDialog:
pass
class rd:
class Ui_Dialog:
pass
else:
HAS_PYQT6 = True
__all__ = ['ReferenceWindow']
[docs]
class ReferenceWindow(QtWidgets.QDialog, rd.Ui_Dialog):
"""
GUI framework for displaying spectral reference lines.
Creates a `Reference Data` window for user interaction. It includes
the following buttons:
- Load List: allows loading reference data files, one at a time.
- Clear Lists: removes all loaded files as well lines and
labels from plots.
Each loaded file can be examined by double-clicking on its listing
in the display window.
There are also two check boxes to control display preferences:
- Show labels: shows or hides text labels for the lines
- Show lines: shows or hides lines and any associated labels
Attributes
----------
signals: sofia_redux.visualization.signals.Signals
Custom signals recognized by the Eye interface, used
to trigger callbacks from user events.
ref_models: reference_model.ReferenceData
The line list data.
visibility: dict
Keys are `ref_line` and `ref_label`. Values are boolean flags
matching the current visibility of lines and labels, respectively.
textview: sofia_redux.visualization.display.text_view.TextView
Text viewer widget.
"""
def __init__(self, parent: Any) -> None:
if not HAS_PYQT6: # pragma: no cover
raise ImportError('PyQt6 package is required for the Eye.')
super(self.__class__, self).__init__(parent)
self.setupUi(self)
self.setModal(0)
self.connections()
self.signals = parent.signals
self.ref_models = parent.reference_models
self.visibility = {'ref_line': False,
'ref_label': False}
self.textview = None
[docs]
def connections(self):
"""
Establish connections to callbacks.
The buttons connect to `load_lines` and `clear_lists`.
The checkboxes connect to `toggle_visibility`. Items
in the file list connect to `show_text`.
"""
self.load_file_button.clicked.connect(self.load_lines)
self.show_lines_box.toggled.connect(
lambda: self.toggle_visibility('ref_line'))
self.show_labels_box.toggled.connect(
lambda: self.toggle_visibility('ref_label'))
self.clear_lists_button.clicked.connect(self.clear_lists)
self.loaded_files_list.itemDoubleClicked.connect(self.show_text)
[docs]
def load_lines(self) -> bool:
"""
Load reference lines from a file.
Returns
-------
result : bool
True if the file is successfully read in; otherwise False.
"""
try:
filename = QtWidgets.QFileDialog.getOpenFileName(
self, caption="Select Line List")[0]
except IndexError:
return False
if not filename:
return False
filename = os.path.normpath(filename)
try:
result = self.ref_models.add_line_list(filename)
except IOError:
result = False
if result:
self.visibility['ref_line'] = True
self.visibility['ref_label'] = True
buttons = [self.show_lines_box,
self.show_labels_box]
for button in buttons:
button.blockSignals(True)
button.setChecked(True)
button.blockSignals(False)
self.set_status(f'Loaded {os.path.basename(filename)}')
# add file name to list widget
item = QtWidgets.QListWidgetItem(os.path.basename(filename))
item.setData(QtCore.Qt.ItemDataRole.UserRole, filename)
item.setToolTip(filename)
self.loaded_files_list.addItem(item)
self.signals.update_reference_lines.emit()
else:
self.set_status(f'Unable to parse '
f'{os.path.basename(filename)}')
return result
[docs]
def toggle_visibility(self, target):
"""
Toggle the visibility for lines or labels.
Parameters
----------
target : {'ref_line', 'ref_label'}
The specific target for which the visibility should be toggled.
Use 'ref_line' for the reference data lines and 'ref_label'
for the reference data labels.
"""
if target == 'ref_line':
state = self.show_lines_box.checkState()
self.ref_models.set_visibility(target, state)
self.signals.update_reference_lines.emit()
elif target == 'ref_label':
state = self.show_labels_box.checkState()
self.ref_models.set_visibility(target, state)
self.signals.update_reference_lines.emit()
else:
state = None
log.debug(f'Invalid visibility target {target}')
if state is not None:
log.debug(f'Updated visibility of {target} to '
f'{self.visibility[target]}')
[docs]
def show_text(self, item):
"""
Show the text of the loaded reference data file.
Parameters
----------
item : QtWidgets.QListWidgetItem
The selected file in the list.
"""
if self.textview is None or not self.textview.isVisible():
self.textview = TextView(self)
self.textview.tableButton.hide()
filename = item.data(QtCore.Qt.ItemDataRole.UserRole)
with open(filename, 'r') as f:
lines = f.readlines()
lines = [ln.strip() for ln in lines]
self.textview.load(lines)
self.textview.show()
self.textview.raise_()
self.textview.setTitle(os.path.basename(filename))
[docs]
def set_status(self, message):
"""
Set a status message.
Parameters
----------
message : str
The message to display.
"""
self.status.setText(message)
[docs]
def clear_status(self):
"""Reset the status bar."""
self.status.setText('')
[docs]
def clear_lists(self):
"""Remove all lines and labels from display."""
# unload data
self.signals.unload_reference_model.emit()
# reset visibility states
self.visibility['ref_line'] = False
self.visibility['ref_label'] = False
buttons = [self.show_lines_box, self.show_labels_box]
for button in buttons:
button.blockSignals(True)
button.setChecked(False)
# clear file list table
self.loaded_files_list.clear()
self.set_status('Cleared line lists')
self.signals.update_reference_lines.emit()