Skip to content

Commit 5456a19

Browse files
subhacomSubhasis Ray
and
Subhasis Ray
authored
Updated Squid demo for PyQt5. Fixes axis of plot of HH-parameters (#84)
* Updated Squid demo for PyQt5. Fixes axis of plot of HH-parameters * Izhikevich demo: removed QWT5 dependency, Squid Demo: minor cleanup * Fixed GUI for Traub model and Izhikevich demo. * Attempted fixing traub model imports. Also some formatting. * Fixes Rall 64 demo --------- Co-authored-by: Subhasis Ray <subhasisray@Subhasiss-MacBook-Pro.local>
1 parent ad5eb49 commit 5456a19

23 files changed

+383
-308
lines changed

izhikevich/demogui_qt.py

Lines changed: 98 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,103 @@
1-
# demo_gui.py ---
2-
#
1+
# demo_gui.py ---
2+
#
33
# Filename: demo_gui.py
4-
# Description:
4+
# Description:
55
# Author: Subhasis Ray
6-
# Maintainer:
6+
# Maintainer:
77
# Created: Wed Jun 16 05:41:58 2010 (+0530)
8-
# Version:
9-
# Last-Updated: Tue Sep 11 14:26:13 2012 (+0530)
10-
# By: subha
11-
# Update #: 318
12-
# URL:
8+
# Version:
9+
# Last-Updated: Tue May 30 15:23:07 2023 (+0530)
10+
# By: Subhasis Ray
11+
# Update #: 489
12+
# URL:
1313

1414
# Change log:
15-
# Tuesday 18 September 2018 09:51:56 AM IST`
15+
# Tuesday 18 September 2018 09:51:56 AM IST`
1616
# Qt Related changes.
1717

18-
try:
19-
from PyQt4 import QtGui, QtCore
20-
from PyQt4.Qt import Qt
21-
except ImportError as e:
22-
print( 'PyQt4 is not found. Doing nothing' )
23-
quit()
18+
import matplotlib.pyplot as plt
19+
import numpy
2420

2521
try:
26-
import PyQt4.Qwt5 as Qwt
22+
from PyQt5.QtWidgets import (
23+
QMainWindow,
24+
QFrame,
25+
QPushButton,
26+
QLabel,
27+
QGridLayout,
28+
QSizePolicy,
29+
QVBoxLayout,
30+
QApplication,
31+
)
32+
33+
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
34+
from matplotlib.backends.backend_qt5agg import (
35+
NavigationToolbar2QT as NavigationToolbar,
36+
)
2737
except ImportError as e:
28-
print( 'PyQt4.Qwt5 not found. Doing nothing' )
38+
print('PyQt5 is not found. Doing nothing')
2939
quit()
30-
31-
import numpy
40+
41+
3242
from Izhikevich import IzhikevichDemo
3343

3444

35-
class IzhikevichGui(QtGui.QMainWindow):
45+
class IzhikevichGui(QMainWindow):
3646
"""This is a Qt version of the GUI"""
47+
3748
def __init__(self, *args):
38-
QtGui.QMainWindow.__init__(self, *args)
49+
QMainWindow.__init__(self, *args)
3950
self.demo = IzhikevichDemo()
40-
self.signalMapper = QtCore.QSignalMapper(self)
41-
self.demoFrame = QtGui.QFrame(self)
42-
self.controlPanel = QtGui.QFrame(self.demoFrame)
43-
self.figureNo = {}
44-
self.buttons = {}
45-
for key, value in list(IzhikevichDemo.parameters.items()):
46-
button = QtGui.QPushButton(key, self.controlPanel)
47-
self.figureNo[value[0]] = key
48-
self.buttons[key] = button
49-
keys = list(self.figureNo.keys())
50-
keys.sort()
51-
length = len(keys)
51+
self.demoFrame = QFrame(self)
52+
self.controlPanel = QFrame(self.demoFrame)
53+
# Map figlabels A-T from Izhi paper to params
54+
# i.e., 'F' -> 'spike_freq_adapt'
55+
self.label_title = {
56+
value[0]: key for key, value in IzhikevichDemo.parameters.items()
57+
}
58+
labels = sorted(self.label_title.keys())
59+
length = len(labels)
5260
rows = int(numpy.rint(numpy.sqrt(length)))
5361
cols = int(numpy.ceil(length * 1.0 / rows))
54-
layout = QtGui.QGridLayout()
55-
for ii in range(rows):
56-
for jj in range(cols):
57-
index = ii * cols + jj
58-
if index < length:
59-
key = self.figureNo[keys[index]]
60-
button = self.buttons[key]
61-
button.setToolTip(self.tr(IzhikevichDemo.documentation[key]))
62-
layout.addWidget(button, ii, jj)
63-
self.connect(button, QtCore.SIGNAL('clicked()'), self.signalMapper, QtCore.SLOT('map()'))
64-
self.signalMapper.setMapping(button, key)
62+
layout = QGridLayout()
63+
for ii, label in enumerate(labels):
64+
row = ii // cols
65+
col = ii % cols
66+
title = self.label_title[label]
67+
button = QPushButton(title, self)
68+
button.setToolTip(self.tr(IzhikevichDemo.documentation[title]))
69+
layout.addWidget(button, row, col)
70+
# NOTE: There is a trick here:
71+
# button.clicked(checked=False) sends a boolean param, but
72+
# we need to ignore that, while storing the associated
73+
# `title` local to the lambda, which is done via the
74+
# keyword param
75+
button.clicked.connect(
76+
lambda checked, key=title: self._simulateAndPlot(key)
77+
)
6578

66-
self.connect(self.signalMapper, QtCore.SIGNAL('mapped(const QString &)'), self._simulateAndPlot)
6779
self.controlPanel.setLayout(layout)
68-
self.plotPanel = QtGui.QFrame(self.demoFrame)
69-
self.VmPlot = Qwt.QwtPlot(self.plotPanel)
70-
self.VmPlot.setAxisTitle(Qwt.QwtPlot.xBottom, 'time (ms)')
71-
self.VmPlot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Vm (mV)')
72-
self.VmPlot.replot()
73-
self.ImPlot = Qwt.QwtPlot(self.plotPanel)
74-
self.ImPlot.setAxisTitle(Qwt.QwtPlot.xBottom, 'time (ms)')
75-
self.ImPlot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Im (nA)')
76-
self.vmPlotZoomer = self._make_zoomer(self.VmPlot)
77-
self.imPlotZoomer = self._make_zoomer(self.ImPlot)
78-
self.descriptionWidget = QtGui.QLabel('Click any of the buttons to simulate and plot the corresponding neuron.')
79-
self.descriptionWidget.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
80-
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
80+
self.figure = plt.figure()
81+
self.plotPanel = FigureCanvas(self.figure)
82+
self.navbar = NavigationToolbar(self.plotPanel, self)
83+
self.VmPlot = self.figure.add_subplot(211)
84+
(self.VmCurve,) = self.VmPlot.plot([], [], label='Vm (mV)')
85+
self.VmPlot.set_xlabel('time (ms)')
86+
self.VmPlot.set_ylabel('Vm (mV)')
87+
self.ImPlot = self.figure.add_subplot(212)
88+
(self.ImCurve,) = self.ImPlot.plot([], [], label='Im (nA)')
89+
self.ImPlot.set_xlabel('time (ms)')
90+
self.ImPlot.set_ylabel('Im (nA)')
91+
self.descriptionWidget = QLabel(
92+
'Click any of the buttons to simulate and plot the corresponding neuron.'
93+
)
94+
self.descriptionWidget.setFrameStyle(QFrame.Panel | QFrame.Sunken)
95+
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
8196
self.descriptionWidget.setSizePolicy(sizePolicy)
82-
self.VmPlot.setSizePolicy(sizePolicy)
83-
self.ImPlot.setSizePolicy(sizePolicy)
84-
layout = QtGui.QVBoxLayout()
85-
layout.addWidget(self.VmPlot)
86-
layout.addWidget(self.ImPlot)
87-
layout.addWidget(self.descriptionWidget)
88-
self.plotPanel.setLayout(layout)
89-
layout = QtGui.QVBoxLayout()
97+
layout = QVBoxLayout()
9098
layout.addWidget(self.plotPanel)
99+
layout.addWidget(self.navbar)
100+
layout.addWidget(self.descriptionWidget)
91101
layout.addWidget(self.controlPanel)
92102
self.demoFrame.setLayout(layout)
93103
self.setCentralWidget(self.demoFrame)
@@ -98,52 +108,36 @@ def _simulateAndPlot(self, key):
98108
doc = IzhikevichDemo.documentation[key].replace('\n', '<br/>')
99109
text = '<b>%s:</b> %s<p><b>Equation:</b><br/> %s' % (key, doc, equationText)
100110
self.descriptionWidget.setText(self.tr(text))
101-
# if key == 'accommodation':
102-
# mbox = QtGui.QMessageBox(self)
103-
# mbox.setText(self.tr('Accommodation cannot be shown with regular Izhikevich model.'))
104-
# mbox.setDetailedText(self.tr('\
105-
# Equation for u for the accommodating neuron is: \
106-
# u\' = a * b * (V + 65)\n Which is different from \
107-
# the regular equation u\' = a * (b*V - u) and cannot \
108-
# be obtained from the latter by any choice of a and b.'))
109-
# mbox.show()
110-
# return
111+
# if key == 'accommodation':
112+
# mbox = QtGui.QMessageBox(self)
113+
# mbox.setText(self.tr('Accommodation cannot be shown with regular Izhikevich model.'))
114+
# mbox.setDetailedText(self.tr('\
115+
# Equation for u for the accommodating neuron is: \
116+
# u\' = a * b * (V + 65)\n Which is different from \
117+
# the regular equation u\' = a * (b*V - u) and cannot \
118+
# be obtained from the latter by any choice of a and b.'))
119+
# mbox.show()
120+
# return
111121
(time, Vm, Im) = self.demo.simulate(key)
112122
Vm = numpy.array(Vm.vector) * 1e3
113123
Im = numpy.array(Im.vector) * 1e9
114-
self.VmPlot.clear()
115-
self.ImPlot.clear()
116-
curve = Qwt.QwtPlotCurve(self.tr(key + '_Vm'))
117-
curve.setPen(QtCore.Qt.red)
118-
curve.setData(time, numpy.array(Vm))
119-
curve.attach(self.VmPlot)
120-
curve = Qwt.QwtPlotCurve(self.tr(key + '_Im'))
121-
curve.setPen(QtCore.Qt.blue)
122-
curve.setData(time, Im)
123-
curve.attach(self.ImPlot)
124-
self.imPlotZoomer.setZoomBase()
125-
self.vmPlotZoomer.setZoomBase()
126-
self.ImPlot.replot()
127-
self.VmPlot.replot()
128-
124+
self.VmCurve.set_data(time, Vm)
125+
self.ImCurve.set_data(time, Im)
126+
self.VmPlot.relim() # Recalculate limits
127+
self.VmPlot.autoscale_view(True, True, True) # Autoscale
128+
self.ImPlot.relim() # Recalculate limits
129+
self.ImPlot.autoscale_view(True, True, True) # Autoscale
130+
self.plotPanel.draw()
131+
self.demoFrame.repaint()
129132

130-
def _make_zoomer(self, plot):
131-
zoomer = Qwt.QwtPlotZoomer(Qwt.QwtPlot.xBottom,
132-
Qwt.QwtPlot.yLeft,
133-
Qwt.QwtPicker.DragSelection,
134-
Qwt.QwtPicker.AlwaysOn,
135-
plot.canvas())
136-
zoomer.setRubberBandPen(QtGui.QPen(QtCore.Qt.white))
137-
zoomer.setTrackerPen(QtGui.QPen(QtCore.Qt.cyan))
138-
return zoomer
139-
140133

141134
import sys
135+
142136
if __name__ == '__main__':
143-
app = QtGui.QApplication(sys.argv)
137+
app = QApplication(sys.argv)
144138
mainWin = IzhikevichGui()
145139
mainWin.show()
146140
sys.exit(app.exec_())
147141

148-
#
142+
#
149143
# demo_gui.py ends here

0 commit comments

Comments
 (0)