-
Notifications
You must be signed in to change notification settings - Fork 0
/
mplot.py
244 lines (204 loc) · 7.72 KB
/
mplot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# mplot.py ---
#
# Filename: mplot.py
# Description:
# Author:
# Maintainer:
# Created: Mon Mar 11 20:24:26 2013 (+0530)
# Version:
# Last-Updated: Wed Jul 3 10:32:35 2013 (+0530)
# By: subha
# Update #: 309
# URL:
# Keywords:
# Compatibility:
#
#
# Commentary:
#
# Moose plot widget default implementation. This should be rich enough
# to suffice for most purposes.
#
#
# Change log:
#
#
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth
# Floor, Boston, MA 02110-1301, USA.
#
#
# Code:
"""
*TODO*
1) Option for default colors, markers, etc.
2) Option for configuring number of rows and columns of
subplots. (I think matplotlib grids will be a bit too much to
implement). Problem is this has to be done before actual axes are
created (as far as I know). Idea: can we do something like movable
widgets example in Qt?
3) Option for selecting any line or set of lines and change its
configuration (as in dataviz).
4) Association between plots and the data source.
5) Lots and lots of scipy/numpy/scikits/statsmodels utilities can be added. To
start with, we should have
a)digital filters
b) fft
c) curve fitting
6) For (5), think of another layer of plugins. Think of this as a
standalone program. All these facilities should again be
pluggable. We do not want to overwhelm novice users with fancy
machine-learning stuff. They should be made available only on
request.
- There is a proposal for data analysis library by Andrew Davison ...
"""
__author__ = "Subhasis Ray"
import sys
import numpy as np
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import Qt
from matplotlib import mlab
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
#from moose import utils
import moose
from PyQt4.QtCore import *
class CanvasWidget(FigureCanvas):
"""Widget to draw plots on.
This class keep track of all the axes in a dictionary. The key for
an axis is its index number in sequence of creation.
next_id: The key for the next axis.
current_id: Key for current axis (anu plotting will happen on
this).
"""
updateSignal = pyqtSignal()
def __init__(self, model, graph, index, *args, **kwargs):
self.model = model
self.graph = graph
self.index = index
# QColor(243, 239, 238, 255)
self.figure = Figure(facecolor = '#F3EFEE')#figsize=(1,1))
FigureCanvas.__init__(self, self.figure, *args, **kwargs)
self.figure.set_canvas(self)
# self.set_xlabel('Time (s)')
# self.set_ylabel('Concentration (mM)')
if len(args) > 0 and isinstance(args[0], QtGui.QWidget):
self.reparent(args[0])
elif (kwargs is not None) and ('parent' in kwargs):
self.reparent(kwargs['parent'])
#self.setAcceptDrops(True)
# self.setMaximumSize(100, 100)
FigureCanvas.updateGeometry(self)
self.axes = {}
self.next_id = 0
self.current_id = -1
tabList = []
self.addTabletoPlot = ''
self.setAcceptDrops(True)
self.gridMode = False
def dragEnterEvent(self, event):
if event.mimeData().hasFormat('text/plain'):
event.acceptProposedAction()
def dragMoveEvent(self, event):
if event.mimeData().hasFormat('text/plain'):
event.acceptProposedAction()
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.Drop):
pass
def dropEvent(self, event):
"""Insert an element of the specified class in drop location"""
if not event.mimeData().hasFormat('text/plain'):
return
# print " active window ", self.isActiveWindow()
# print "Mouse : ", self.mouse
# pos = self.mapFromGlobal(QCursor.pos())
# print "Mouse Position : ", pos
modelRoot, element = event.mimeData().data
if isinstance (element,moose.PoolBase):
tablePath = moose.utils.create_table_path(self.model, self.graph, element, "Conc")
table = moose.utils.create_table(tablePath, element, "Conc","Table2")
# moose.connect(table, 'requestOut', element, 'getConc')
self.updateSignal.emit()
elif isinstance(element, moose.CompartmentBase):
tablePath = moose.utils.create_table_path(self.model, self.graph, element, "Vm")
table = moose.utils.create_table(tablePath, element, "Vm","Table")
self.updateSignal.emit()
else:
QtGui.QMessageBox.question(self, 'Message',"This element's properties cannot be plotted.", QtGui.QMessageBox.Ok)
def addSubplot(self, rows, cols):
"""Add a subplot to figure and set it as current axes."""
assert(self.next_id <= rows * cols)
axes = self.figure.add_subplot(rows, cols, self.next_id+1)
axes.set_xlabel("Time (s)")
axes.set_ylabel("Concentration (mM)")
axes.set_xlim(left=0.0)
axes.set_ylim(bottom=0.0)
self.axes[self.next_id] = axes
axes.set_title("Graph " + str(self.index + 1))
self.current_id = self.next_id
self.next_id += 1
labelList = []
axes.legend(loc='upper center')
return axes
def plot(self, *args, **kwargs):
#self.callAxesFn('legend',loc='lower center',bbox_to_anchor=(0.5, -0.03),fancybox=True, shadow=True, ncol=3)
return self.callAxesFn('plot', *args, **kwargs)
def callAxesFn(self, fname, *args, **kwargs):
"""Call any arbitrary function of current axes object."""
if self.current_id < 0:
self.addSubplot(1,1)
fn = eval('self.axes[self.current_id].%s' % (fname))
return fn(*args, **kwargs)
def resize_event(self, event):
print("Resize event called ", event)
def toggleGrid(self):
self.gridMode = not self.gridMode
for key in self.axes:
self.axes[key].grid(self.gridMode)
self.draw()
def setXLimit(self, minX, maxX):
for key in self.axes:
self.axes[key].set_xlim([minX, maxX])
self.draw()
import sys
import os
import config
import unittest
from PyQt4.QtTest import QTest
class CanvasWidgetTests(unittest.TestCase):
def setUp(self):
self.app = QtGui.QApplication([])
QtGui.qApp = self.app
icon = QtGui.QIcon(os.path.join(config.KEY_ICON_DIR,'moose_icon.png'))
self.app.setWindowIcon(icon)
self.window = QtGui.QMainWindow()
self.cwidget = CanvasWidget()
self.window.setCentralWidget(self.cwidget)
self.window.show()
def testPlot(self):
"""Test plot function"""
self.cwidget.addSubplot(1,1)
self.cwidget.plot(np.arange(1000), mlab.normpdf(np.arange(1000), 500, 150))
def testCallAxesFn(self):
self.cwidget.addSubplot(1,1)
self.cwidget.callAxesFn('scatter', np.random.randint(0, 100, 100), np.random.randint(0, 100,100))
def tearDown(self):
self.app.exec_()
if __name__ == '__main__':
unittest.main()
#
# mplot.py ends here