Skip to content

Commit

Permalink
DataLog viewer tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelClerx committed May 16, 2023
1 parent 695edea commit 8ac4b1c
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This page lists the main changes made to Myokit in each release.
- [#909](https://github.com/MichaelClerx/myokit/pull/909) Myokit is no longer tested on Python 3.6.
- [#918](https://github.com/myokit/myokit/pull/918) The only argument to `Variable.promote` has been renamed from `state_value` to `initial_value`.
- [#918](https://github.com/myokit/myokit/pull/918) `Model.import_component` now preserves the ordering of the imported states.
- [#951](https://github.com/myokit/myokit/pull/951) The DataLogViewer now overlaps traces with numbering (e.g. 0.membrane.V and 1.membrane.V), and toggles between files and variables with Page up and down Or Ctrl+Page up and down.
- Deprecated
- [#918](https://github.com/myokit/myokit/pull/918) `Model.state` is deprecated in favour of `Model.initial_values`.
- [#918](https://github.com/myokit/myokit/pull/918) `Model.set_state` is deprecated in favour of `Model.set_initial_values`.
Expand Down
168 changes: 152 additions & 16 deletions myokit/gui/datalog_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,11 @@ def __init__(self, *filenames):
cp = QtWidgets.QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
# Add widget for Abf file tabs
self._tabs = QtWidgets.QTabWidget()
# Add widget for file tabs
self._tabs = TabWidget()
self._tabs.setTabsClosable(True)
self._tabs.tabCloseRequested.connect(self.action_close)
self._tabs.currentChanged.connect(self.fileTabChangeEvent)
self.setCentralWidget(self._tabs)
# Menu bar
self.create_menu()
Expand All @@ -146,8 +147,16 @@ def action_close(self, index):
"""
Called when a tab should be closed
"""
# Remove tab
tab = self._tabs.widget(index)
self._tabs.removeTab(index)

# Update buttons
if self._tabs.count() < 2:
self._tool_next_file.setEnabled(False)
self._tool_prev_file.setEnabled(False)

# Delete tab
if tab is not None:
tab.deleteLater()
gc.collect()
Expand All @@ -168,13 +177,49 @@ def action_open(self):
if filenames:
# Save current number of tabs
tab_count = self._tabs.count()

# Load files
for filename in filenames:
self.load_file(str(filename))

# If loading went ok, show first of newly loaded files
if self._tabs.count() > tab_count:
tab_count_new = self._tabs.count()
if tab_count_new > tab_count:
self._tabs.setCurrentIndex(tab_count)

# Enable next/previous file menu items
if tab_count_new > 1:
self._tool_next_file.setEnabled(True)
self._tool_prev_file.setEnabled(True)

def action_next_file(self):
"""
Select the next open file.
"""
self._tabs.next()

def action_next_var(self):
"""
Select the next variable in the selected file.
"""
tab = self._tabs.currentWidget()
if tab:
tab.next()

def action_prev_file(self):
"""
Select the previous open file.
"""
self._tabs.previous()

def action_prev_var(self):
"""
Select the previous variable in the selected file
"""
tab = self._tabs.currentWidget()
if tab:
tab.previous()

def closeEvent(self, event=None):
"""
Called when window is closed. To force a close (and trigger this
Expand Down Expand Up @@ -211,6 +256,37 @@ def create_menu(self):
self._tool_exit.setIcon(QtGui.QIcon.fromTheme('application-exit'))
self._tool_exit.triggered.connect(self.close)
self._menu_file.addAction(self._tool_exit)
# View menu
self._menu_view = self._menu.addMenu('&View')
# View > Next file
self._tool_next_file = QtWidgets.QAction('Next file', self)
self._tool_next_file.setShortcut('Ctrl+PgDown')
self._tool_next_file.setStatusTip('Select the next open file')
self._tool_next_file.triggered.connect(self.action_next_file)
self._tool_next_file.setEnabled(False)
self._menu_view.addAction(self._tool_next_file)
# View > Previous file
self._menu_view.addAction(self._tool_next_file)
self._tool_prev_file = QtWidgets.QAction('Previous file', self)
self._tool_prev_file.setShortcut('Ctrl+PgUp')
self._tool_prev_file.setStatusTip('Select the previous open file')
self._tool_prev_file.triggered.connect(self.action_prev_file)
self._tool_prev_file.setEnabled(False)
self._menu_view.addAction(self._tool_prev_file)
# View > Next variable
self._tool_next_var = QtWidgets.QAction('Next variable', self)
self._tool_next_var.setShortcut('PgDown')
self._tool_next_var.setStatusTip('Show the next variable')
self._tool_next_var.triggered.connect(self.action_next_var)
self._tool_next_var.setEnabled(False)
self._menu_view.addAction(self._tool_next_var)
# View > Previous var
self._tool_prev_var = QtWidgets.QAction('Previous variable', self)
self._tool_prev_var.setShortcut('PgUp')
self._tool_prev_var.setStatusTip('Show the previous variable')
self._tool_prev_var.triggered.connect(self.action_prev_var)
self._tool_prev_var.setEnabled(False)
self._menu_view.addAction(self._tool_prev_var)
# Help menu
self._menu_help = self._menu.addMenu('&Help')
# Help > About
Expand Down Expand Up @@ -411,8 +487,46 @@ def show(self):
super(DataLogViewer, self).show()
QtWidgets.QApplication.processEvents()

def fileTabChangeEvent(self, index):
"""
Different file tab selected.
"""
if index >= 0:
tab = self._tabs.widget(index)
if tab.count() > 1:
self._tool_prev_var.setEnabled(True)
self._tool_next_var.setEnabled(True)
return
self._tool_prev_var.setEnabled(False)
self._tool_next_var.setEnabled(False)


class AbfTab(QtWidgets.QTabWidget):
class TabWidget(QtWidgets.QTabWidget):
"""
Tab widget that can move up and down when asked.
"""
def next(self):
"""
Select the next widget.
"""
n = self.count()
if n < 2:
return
i = self.currentIndex() + 1
self.setCurrentIndex(0 if i >= n else i)

def previous(self):
"""
Select the previous widget.
"""
n = self.count()
if n < 2:
return
i = self.currentIndex() - 1
self.setCurrentIndex(n - 1 if i < 0 else i)


class AbfTab(TabWidget):
"""
A widget displaying an ABF file.
"""
Expand Down Expand Up @@ -514,7 +628,7 @@ def deleteLater(self):
super(AbfTab, self).deleteLater()


class AtfTab(QtWidgets.QTabWidget):
class AtfTab(TabWidget):
"""
A widget displaying an AGF file.
"""
Expand Down Expand Up @@ -585,7 +699,7 @@ def deleteLater(self):
super(AtfTab, self).deleteLater()


class CsvTab(QtWidgets.QTabWidget):
class CsvTab(TabWidget):
"""
A widget displaying a CSV file.
Expand Down Expand Up @@ -619,17 +733,33 @@ def __init__(self, parent, log, filename):
self, TITLE, 'Unable to load file: no data found.')
return

# Add tab for each column
for k, v in log.items():
if k == time:
# Overlapping sweeps or neighbouring cells?
keys = []
groups = {}
for key in log.keys():
if key == time:
continue
self.addTab(self.create_graph_tab(k, v), k)
index, var = myokit.split_key(key)
if index:
group = groups.get(var, None)
if group is None:
groups[var] = [index]
keys.append(var)
else:
group.append(index)
else:
keys.append(var)

# Add tab for each column
for k in keys:
self.addTab(self.create_graph_tab(k, groups.get(k)), k)

def create_graph_tab(self, key, data):
def create_graph_tab(self, key, indices=None):
"""
Creates a widget displaying the ``data`` stored under ``key``.
Creates a widget displaying the data stored under ``key``.
"""
widget = QtWidgets.QWidget(self)

# Create figure
figure = matplotlib.figure.Figure()
figure.suptitle(self._filename)
Expand All @@ -638,8 +768,14 @@ def create_graph_tab(self, key, data):
axes = figure.add_subplot(1, 1, 1)
axes.set_title(key)
toolbar = backend.NavigationToolbar2QT(canvas, widget)

# Draw lines
axes.plot(self._time, data)
if indices is None:
axes.plot(self._time, self._log[key])
else:
for i in indices:
axes.plot(self._time, self._log[i + key])

# Create a layout
vbox = QtWidgets.QVBoxLayout()
vbox.addWidget(canvas)
Expand All @@ -662,7 +798,7 @@ def deleteLater(self):
super(CsvTab, self).deleteLater()


class MatTab(QtWidgets.QTabWidget):
class MatTab(TabWidget):
"""
A widget displaying a MAT file.
"""
Expand Down Expand Up @@ -750,7 +886,7 @@ def deleteLater(self):
super(MatTab, self).deleteLater()


class TxtTab(QtWidgets.QTabWidget):
class TxtTab(TabWidget):
"""
A widget displaying a TXT file (with lots of heuristics!).
"""
Expand Down Expand Up @@ -832,7 +968,7 @@ def deleteLater(self):
super(TxtTab, self).deleteLater()


class WcpTab(QtWidgets.QTabWidget):
class WcpTab(TabWidget):
"""
A widget displaying a WCP file.
"""
Expand Down

0 comments on commit 8ac4b1c

Please sign in to comment.