Added matplotlib exporter
Updates to MeshData class (this is still not tested)
This commit is contained in:
parent
c814499bee
commit
f6da6e2fd0
@ -72,6 +72,8 @@ class ExportDialog(QtGui.QWidget):
|
||||
|
||||
|
||||
def exportItemChanged(self, item, prev):
|
||||
if item is None:
|
||||
return
|
||||
if item.gitem is self.scene:
|
||||
newBounds = self.scene.views()[0].viewRect()
|
||||
else:
|
||||
@ -105,7 +107,10 @@ class ExportDialog(QtGui.QWidget):
|
||||
expClass = self.exporterClasses[str(item.text())]
|
||||
exp = expClass(item=self.ui.itemTree.currentItem().gitem)
|
||||
params = exp.parameters()
|
||||
self.ui.paramTree.setParameters(params)
|
||||
if params is None:
|
||||
self.ui.paramTree.clear()
|
||||
else:
|
||||
self.ui.paramTree.setParameters(params)
|
||||
self.currentExporter = exp
|
||||
|
||||
def exportClicked(self):
|
||||
|
@ -57,7 +57,7 @@ renamePyc(path)
|
||||
## don't import the more complex systems--canvas, parametertree, flowchart, dockarea
|
||||
## these must be imported separately.
|
||||
|
||||
def importAll(path):
|
||||
def importAll(path, excludes=()):
|
||||
d = os.path.join(os.path.split(__file__)[0], path)
|
||||
files = []
|
||||
for f in os.listdir(d):
|
||||
@ -67,6 +67,8 @@ def importAll(path):
|
||||
files.append(f[:-3])
|
||||
|
||||
for modName in files:
|
||||
if modName in excludes:
|
||||
continue
|
||||
mod = __import__(path+"."+modName, globals(), locals(), fromlist=['*'])
|
||||
if hasattr(mod, '__all__'):
|
||||
names = mod.__all__
|
||||
@ -77,7 +79,7 @@ def importAll(path):
|
||||
globals()[k] = getattr(mod, k)
|
||||
|
||||
importAll('graphicsItems')
|
||||
importAll('widgets')
|
||||
importAll('widgets', excludes=['MatplotlibWidget'])
|
||||
|
||||
from imageview import *
|
||||
from WidgetGroup import *
|
||||
|
74
exporters/Matplotlib.py
Normal file
74
exporters/Matplotlib.py
Normal file
@ -0,0 +1,74 @@
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
from Exporter import Exporter
|
||||
|
||||
|
||||
__all__ = ['MatplotlibExporter']
|
||||
|
||||
|
||||
class MatplotlibExporter(Exporter):
|
||||
Name = "Matplotlib Window"
|
||||
windows = []
|
||||
def __init__(self, item):
|
||||
Exporter.__init__(self, item)
|
||||
|
||||
def parameters(self):
|
||||
return None
|
||||
|
||||
def export(self, fileName=None):
|
||||
|
||||
if isinstance(self.item, pg.PlotItem):
|
||||
mpw = MatplotlibWindow()
|
||||
MatplotlibExporter.windows.append(mpw)
|
||||
fig = mpw.getFigure()
|
||||
|
||||
ax = fig.add_subplot(111)
|
||||
ax.clear()
|
||||
#ax.grid(True)
|
||||
|
||||
for item in self.item.curves:
|
||||
x, y = item.getData()
|
||||
opts = item.opts
|
||||
pen = pg.mkPen(opts['pen'])
|
||||
if pen.style() == QtCore.Qt.NoPen:
|
||||
linestyle = ''
|
||||
else:
|
||||
linestyle = '-'
|
||||
color = tuple([c/255. for c in pg.colorTuple(pen.color())])
|
||||
symbol = opts['symbol']
|
||||
if symbol == 't':
|
||||
symbol = '^'
|
||||
symbolPen = pg.mkPen(opts['symbolPen'])
|
||||
symbolBrush = pg.mkBrush(opts['symbolBrush'])
|
||||
markeredgecolor = tuple([c/255. for c in pg.colorTuple(symbolPen.color())])
|
||||
markerfacecolor = tuple([c/255. for c in pg.colorTuple(symbolBrush.color())])
|
||||
|
||||
if opts['fillLevel'] is not None and opts['fillBrush'] is not None:
|
||||
fillBrush = pg.mkBrush(opts['fillBrush'])
|
||||
fillcolor = tuple([c/255. for c in pg.colorTuple(fillBrush.color())])
|
||||
ax.fill_between(x=x, y1=y, y2=opts['fillLevel'], facecolor=fillcolor)
|
||||
|
||||
ax.plot(x, y, marker=symbol, color=color, linewidth=pen.width(), linestyle=linestyle, markeredgecolor=markeredgecolor, markerfacecolor=markerfacecolor)
|
||||
|
||||
xr, yr = self.item.viewRange()
|
||||
ax.set_xbound(*xr)
|
||||
ax.set_ybound(*yr)
|
||||
mpw.draw()
|
||||
else:
|
||||
raise Exception("Matplotlib export currently only works with plot items")
|
||||
|
||||
|
||||
|
||||
class MatplotlibWindow(QtGui.QMainWindow):
|
||||
def __init__(self):
|
||||
import pyqtgraph.widgets.MatplotlibWidget
|
||||
QtGui.QMainWindow.__init__(self)
|
||||
self.mpl = pyqtgraph.widgets.MatplotlibWidget.MatplotlibWidget()
|
||||
self.setCentralWidget(self.mpl)
|
||||
self.show()
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.mpl, attr)
|
||||
|
||||
def closeEvent(self, ev):
|
||||
MatplotlibExporter.windows.remove(self)
|
177
functions.py
177
functions.py
@ -409,12 +409,12 @@ def affineSlice(data, shape, origin, vectors, axes, **kargs):
|
||||
|
||||
|
||||
|
||||
def makeARGB(data, lut=None, levels=None, useRGBA=False):
|
||||
def makeARGB(data, lut=None, levels=None):
|
||||
"""
|
||||
Convert a 2D or 3D array into an ARGB array suitable for building QImages
|
||||
Will optionally do scaling and/or table lookups to determine final colors.
|
||||
|
||||
Returns the ARGB array (values 0-255) and a boolean indicating whether there is alpha channel data.
|
||||
Returns the ARGB array and a boolean indicating whether there is alpha channel data.
|
||||
|
||||
Arguments:
|
||||
data - 2D or 3D numpy array of int/float types
|
||||
@ -433,8 +433,6 @@ def makeARGB(data, lut=None, levels=None, useRGBA=False):
|
||||
Lookup tables can be built using GradientWidget.
|
||||
levels - List [min, max]; optionally rescale data before converting through the
|
||||
lookup table. rescaled = (data-min) * len(lut) / (max-min)
|
||||
useRGBA - If True, the data is returned in RGBA order. The default is
|
||||
False, which returns in BGRA order for use with QImage.
|
||||
|
||||
"""
|
||||
|
||||
@ -582,11 +580,8 @@ def makeARGB(data, lut=None, levels=None, useRGBA=False):
|
||||
|
||||
prof.mark('4')
|
||||
|
||||
if useRGBA:
|
||||
order = [0,1,2,3] ## array comes out RGBA
|
||||
else:
|
||||
order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image.
|
||||
|
||||
order = [2,1,0,3] ## for some reason, the colors line up as BGR in the final image.
|
||||
if data.shape[2] == 1:
|
||||
for i in xrange(3):
|
||||
imgData[..., order[i]] = data[..., 0]
|
||||
@ -737,84 +732,6 @@ def rescaleData(data, scale, offset):
|
||||
#return facets
|
||||
|
||||
|
||||
def isocurve(data, level):
|
||||
"""
|
||||
Generate isocurve from 2D data using marching squares algorithm.
|
||||
|
||||
*data* 2D numpy array of scalar values
|
||||
*level* The level at which to generate an isosurface
|
||||
|
||||
This function is SLOW; plenty of room for optimization here.
|
||||
"""
|
||||
|
||||
sideTable = [
|
||||
[],
|
||||
[0,1],
|
||||
[1,2],
|
||||
[0,2],
|
||||
[0,3],
|
||||
[1,3],
|
||||
[0,1,2,3],
|
||||
[2,3],
|
||||
[2,3],
|
||||
[0,1,2,3],
|
||||
[1,3],
|
||||
[0,3],
|
||||
[0,2],
|
||||
[1,2],
|
||||
[0,1],
|
||||
[]
|
||||
]
|
||||
|
||||
edgeKey=[
|
||||
[(0,1),(0,0)],
|
||||
[(0,0), (1,0)],
|
||||
[(1,0), (1,1)],
|
||||
[(1,1), (0,1)]
|
||||
]
|
||||
|
||||
|
||||
lines = []
|
||||
|
||||
## mark everything below the isosurface level
|
||||
mask = data < level
|
||||
|
||||
### make four sub-fields and compute indexes for grid cells
|
||||
index = np.zeros([x-1 for x in data.shape], dtype=np.ubyte)
|
||||
fields = np.empty((2,2), dtype=object)
|
||||
slices = [slice(0,-1), slice(1,None)]
|
||||
for i in [0,1]:
|
||||
for j in [0,1]:
|
||||
fields[i,j] = mask[slices[i], slices[j]]
|
||||
#vertIndex = i - 2*j*i + 3*j + 4*k ## this is just to match Bourk's vertex numbering scheme
|
||||
vertIndex = i+2*j
|
||||
#print i,j,k," : ", fields[i,j,k], 2**vertIndex
|
||||
index += fields[i,j] * 2**vertIndex
|
||||
#print index
|
||||
#print index
|
||||
|
||||
## add lines
|
||||
for i in xrange(index.shape[0]): # data x-axis
|
||||
for j in xrange(index.shape[1]): # data y-axis
|
||||
sides = sideTable[index[i,j]]
|
||||
for l in range(0, len(sides), 2): ## faces for this grid cell
|
||||
edges = sides[l:l+2]
|
||||
pts = []
|
||||
for m in [0,1]: # points in this face
|
||||
p1 = edgeKey[edges[m]][0] # p1, p2 are points at either side of an edge
|
||||
p2 = edgeKey[edges[m]][1]
|
||||
v1 = data[i+p1[0], j+p1[1]] # v1 and v2 are the values at p1 and p2
|
||||
v2 = data[i+p2[0], j+p2[1]]
|
||||
f = (level-v1) / (v2-v1)
|
||||
fi = 1.0 - f
|
||||
p = ( ## interpolate between corners
|
||||
p1[0]*fi + p2[0]*f + i + 0.5,
|
||||
p1[1]*fi + p2[1]*f + j + 0.5
|
||||
)
|
||||
pts.append(p)
|
||||
lines.append(pts)
|
||||
|
||||
return lines ## a list of pairs of points
|
||||
|
||||
|
||||
def isosurface(data, level):
|
||||
@ -1193,55 +1110,55 @@ def isosurface(data, level):
|
||||
|
||||
return facets
|
||||
|
||||
## code has moved to opengl/MeshData.py
|
||||
#def meshNormals(data):
|
||||
#"""
|
||||
#Return list of normal vectors and list of faces which reference the normals
|
||||
#data must be list of triangles; each triangle is a list of three points
|
||||
#[ [(x,y,z), (x,y,z), (x,y,z)], ...]
|
||||
#Return values are
|
||||
#normals: [(x,y,z), ...]
|
||||
#faces: [(n1, n2, n3), ...]
|
||||
#"""
|
||||
|
||||
def meshNormals(data):
|
||||
"""
|
||||
Return list of normal vectors and list of faces which reference the normals
|
||||
data must be list of triangles; each triangle is a list of three points
|
||||
[ [(x,y,z), (x,y,z), (x,y,z)], ...]
|
||||
Return values are
|
||||
normals: [(x,y,z), ...]
|
||||
faces: [(n1, n2, n3), ...]
|
||||
"""
|
||||
#normals = []
|
||||
#points = {}
|
||||
#for i, face in enumerate(data):
|
||||
### compute face normal
|
||||
#pts = [QtGui.QVector3D(*x) for x in face]
|
||||
#norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
|
||||
#normals.append(norm)
|
||||
|
||||
normals = []
|
||||
points = {}
|
||||
for i, face in enumerate(data):
|
||||
## compute face normal
|
||||
pts = [QtGui.QVector3D(*x) for x in face]
|
||||
norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
|
||||
normals.append(norm)
|
||||
### remember each point was associated with this normal
|
||||
#for p in face:
|
||||
#p = tuple(map(lambda x: np.round(x, 8), p))
|
||||
#if p not in points:
|
||||
#points[p] = []
|
||||
#points[p].append(i)
|
||||
|
||||
## remember each point was associated with this normal
|
||||
for p in face:
|
||||
p = tuple(map(lambda x: np.round(x, 8), p))
|
||||
if p not in points:
|
||||
points[p] = []
|
||||
points[p].append(i)
|
||||
### compute averages
|
||||
#avgLookup = {}
|
||||
#avgNorms = []
|
||||
#for k,v in points.iteritems():
|
||||
#norms = [normals[i] for i in v]
|
||||
#a = norms[0]
|
||||
#if len(v) > 1:
|
||||
#for n in norms[1:]:
|
||||
#a = a + n
|
||||
#a = a / len(v)
|
||||
#avgLookup[k] = len(avgNorms)
|
||||
#avgNorms.append(a)
|
||||
|
||||
## compute averages
|
||||
avgLookup = {}
|
||||
avgNorms = []
|
||||
for k,v in points.iteritems():
|
||||
norms = [normals[i] for i in v]
|
||||
a = norms[0]
|
||||
if len(v) > 1:
|
||||
for n in norms[1:]:
|
||||
a = a + n
|
||||
a = a / len(v)
|
||||
avgLookup[k] = len(avgNorms)
|
||||
avgNorms.append(a)
|
||||
### generate return array
|
||||
#faces = []
|
||||
#for i, face in enumerate(data):
|
||||
#f = []
|
||||
#for p in face:
|
||||
#p = tuple(map(lambda x: np.round(x, 8), p))
|
||||
#f.append(avgLookup[p])
|
||||
#faces.append(tuple(f))
|
||||
|
||||
## generate return array
|
||||
faces = []
|
||||
for i, face in enumerate(data):
|
||||
f = []
|
||||
for p in face:
|
||||
p = tuple(map(lambda x: np.round(x, 8), p))
|
||||
f.append(avgLookup[p])
|
||||
faces.append(tuple(f))
|
||||
|
||||
return avgNorms, faces
|
||||
#return avgNorms, faces
|
||||
|
||||
|
||||
|
||||
|
@ -98,7 +98,7 @@ class PlotDataItem(GraphicsObject):
|
||||
'pen': (200,200,200),
|
||||
'shadowPen': None,
|
||||
'fillLevel': None,
|
||||
'brush': None,
|
||||
'fillBrush': None,
|
||||
|
||||
'symbol': None,
|
||||
'symbolSize': 10,
|
||||
@ -165,11 +165,14 @@ class PlotDataItem(GraphicsObject):
|
||||
#self.update()
|
||||
self.updateItems()
|
||||
|
||||
def setBrush(self, *args, **kargs):
|
||||
def setFillBrush(self, *args, **kargs):
|
||||
brush = fn.mkBrush(*args, **kargs)
|
||||
self.opts['brush'] = brush
|
||||
self.opts['fillBrush'] = brush
|
||||
self.updateItems()
|
||||
|
||||
def setBrush(self, *args, **kargs):
|
||||
return self.setFillBrush(*args, **kargs)
|
||||
|
||||
def setFillLevel(self, level):
|
||||
self.opts['fillLevel'] = level
|
||||
self.updateItems()
|
||||
@ -268,6 +271,9 @@ class PlotDataItem(GraphicsObject):
|
||||
if 'symbol' not in kargs and ('symbolPen' in kargs or 'symbolBrush' in kargs or 'symbolSize' in kargs):
|
||||
kargs['symbol'] = 'o'
|
||||
|
||||
if 'brush' in kargs:
|
||||
kargs['fillBrush'] = kargs['brush']
|
||||
|
||||
for k in self.opts.keys():
|
||||
if k in kargs:
|
||||
self.opts[k] = kargs[k]
|
||||
@ -313,8 +319,8 @@ class PlotDataItem(GraphicsObject):
|
||||
#c.scene().removeItem(c)
|
||||
|
||||
curveArgs = {}
|
||||
for k in ['pen', 'shadowPen', 'fillLevel', 'brush']:
|
||||
curveArgs[k] = self.opts[k]
|
||||
for k,v in [('pen','pen'), ('shadowPen','shadowPen'), ('fillLevel','fillLevel'), ('fillBrush', 'brush')]:
|
||||
curveArgs[v] = self.opts[k]
|
||||
|
||||
scatterArgs = {}
|
||||
for k,v in [('symbolPen','pen'), ('symbolBrush','brush'), ('symbol','symbol'), ('symbolSize', 'size')]:
|
||||
|
@ -146,11 +146,11 @@ class PlotItem(GraphicsWidget):
|
||||
|
||||
|
||||
## Wrap a few methods from viewBox
|
||||
for m in [
|
||||
'setXRange', 'setYRange', 'setXLink', 'setYLink',
|
||||
'setRange', 'autoRange', 'viewRect', 'setMouseEnabled',
|
||||
'enableAutoRange', 'disableAutoRange', 'setAspectLocked']:
|
||||
setattr(self, m, getattr(self.vb, m))
|
||||
#for m in [
|
||||
#'setXRange', 'setYRange', 'setXLink', 'setYLink',
|
||||
#'setRange', 'autoRange', 'viewRect', 'setMouseEnabled',
|
||||
#'enableAutoRange', 'disableAutoRange', 'setAspectLocked']:
|
||||
#setattr(self, m, getattr(self.vb, m))
|
||||
|
||||
self.items = []
|
||||
self.curves = []
|
||||
@ -296,6 +296,8 @@ class PlotItem(GraphicsWidget):
|
||||
#QtGui.QGraphicsWidget.paint(self, *args)
|
||||
#prof.finish()
|
||||
|
||||
def __getattr__(self, attr): ## wrap ms
|
||||
return getattr(self.vb, attr)
|
||||
|
||||
def close(self):
|
||||
#print "delete", self
|
||||
|
@ -8,18 +8,117 @@ class MeshData(object):
|
||||
- normals per vertex or tri
|
||||
"""
|
||||
|
||||
def __init__(self ...):
|
||||
def __init__(self):
|
||||
self.vertexes = []
|
||||
self.edges = None
|
||||
self.faces = []
|
||||
self.vertexFaces = None ## maps vertex ID to a list of face IDs
|
||||
self.vertexNormals = None
|
||||
self.faceNormals = None
|
||||
self.vertexColors = None
|
||||
self.edgeColors = None
|
||||
self.faceColors = None
|
||||
|
||||
def setFaces(self, faces, vertexes=None):
|
||||
"""
|
||||
Set the faces in this data set.
|
||||
Data may be provided either as an Nx3x3 list of floats (9 float coordinate values per face)
|
||||
*faces* = [ [(x, y, z), (x, y, z), (x, y, z)], ... ]
|
||||
or as an Nx3 list of ints (vertex integers) AND an Mx3 list of floats (3 float coordinate values per vertex)
|
||||
*faces* = [ (p1, p2, p3), ... ]
|
||||
*vertexes* = [ (x, y, z), ... ]
|
||||
"""
|
||||
|
||||
if vertexes is None:
|
||||
self._setUnindexedFaces(self, faces)
|
||||
else:
|
||||
self._setIndexedFaces(self, faces)
|
||||
|
||||
def _setUnindexedFaces(self, faces):
|
||||
verts = {}
|
||||
self.faces = []
|
||||
self.vertexes = []
|
||||
self.vertexFaces = []
|
||||
self.faceNormals = None
|
||||
self.vertexNormals = None
|
||||
for face in faces:
|
||||
inds = []
|
||||
for pt in face:
|
||||
pt2 = tuple([int(x*1e14) for x in pt]) ## quantize to be sure that nearly-identical points will be merged
|
||||
index = verts.get(pt2, None)
|
||||
if index is None:
|
||||
self.vertexes.append(tuple(pt))
|
||||
self.vertexFaces.append([])
|
||||
index = len(self.vertexes)-1
|
||||
verts[pt2] = index
|
||||
self.vertexFaces[index].append(face)
|
||||
inds.append(index)
|
||||
self.faces.append(tuple(inds))
|
||||
|
||||
def _setIndexedFaces(self, faces, vertexes):
|
||||
self.vertexes = vertexes
|
||||
self.faces = faces
|
||||
self.edges = None
|
||||
self.vertexFaces = None
|
||||
self.faceNormals = None
|
||||
self.vertexNormals = None
|
||||
|
||||
def getVertexFaces(self):
|
||||
"""
|
||||
Return list mapping each vertex index to a list of face indexes that use the vertex.
|
||||
"""
|
||||
if self.vertexFaces is None:
|
||||
self.vertexFaces = [[]] * len(self.vertexes)
|
||||
for i, face in enumerate(self.faces):
|
||||
for ind in face:
|
||||
if len(self.vertexFaces[ind]) == 0:
|
||||
self.vertexFaces[ind] = [] ## need a unique/empty list to fill
|
||||
self.vertexFaces[ind].append(i)
|
||||
return self.vertexFaces
|
||||
|
||||
|
||||
def generateFaceNormals(self):
|
||||
def getFaceNormals(self):
|
||||
"""
|
||||
Computes and stores normal of each face.
|
||||
"""
|
||||
if self.faceNormals is None:
|
||||
self.faceNormals = []
|
||||
for i, face in enumerate(self.faces):
|
||||
## compute face normal
|
||||
pts = [QtGui.QVector3D(*self.vertexes[vind]) for vind in face]
|
||||
norm = QtGui.QVector3D.crossProduct(pts[1]-pts[0], pts[2]-pts[0])
|
||||
self.faceNormals.append(norm)
|
||||
return self.faceNormals
|
||||
|
||||
|
||||
def generateVertexNormals(self):
|
||||
def getVertexNormals(self):
|
||||
"""
|
||||
Assigns each vertex the average of its connected face normals.
|
||||
If face normals have not been computed yet, then generateFaceNormals will be called.
|
||||
"""
|
||||
if self.vertexNormals is None:
|
||||
faceNorms = self.getFaceNormals()
|
||||
vertFaces = self.getVertexFaces()
|
||||
self.vertexNormals = []
|
||||
for vindex in xrange(len(self.vertexes)):
|
||||
norms = [faceNorms[findex] for findex in vertFaces[vindex]]
|
||||
if len(norms) == 0:
|
||||
norm = QtGui.QVector3D()
|
||||
else:
|
||||
norm = reduce(QtGui.QVector3D.__add__, facenorms) / float(len(norms))
|
||||
self.vertexNormals.append(norm)
|
||||
return self.vertexNormals
|
||||
|
||||
|
||||
def reverseNormals(self):
|
||||
"""
|
||||
Reverses the direction of all normal vectors.
|
||||
"""
|
||||
pass
|
||||
|
||||
def generateEdgesFromFaces(self):
|
||||
"""
|
||||
Generate a set of edges by listing all the edges of faces and removing any duplicates.
|
||||
Useful for displaying wireframe meshes.
|
||||
"""
|
||||
pass
|
||||
|
37
widgets/MatplotlibWidget.py
Normal file
37
widgets/MatplotlibWidget.py
Normal file
@ -0,0 +1,37 @@
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
import matplotlib
|
||||
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
class MatplotlibWidget(QtGui.QWidget):
|
||||
"""
|
||||
Implements a Matplotlib figure inside a QWidget.
|
||||
Use getFigure() and redraw() to interact with matplotlib.
|
||||
|
||||
Example::
|
||||
|
||||
mw = MatplotlibWidget()
|
||||
subplot = mw.getFigure().add_subplot(111)
|
||||
subplot.plot(x,y)
|
||||
mw.draw()
|
||||
"""
|
||||
|
||||
def __init__(self, size=(5.0, 4.0), dpi=100):
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.fig = Figure(size, dpi=dpi)
|
||||
self.canvas = FigureCanvas(self.fig)
|
||||
self.canvas.setParent(self)
|
||||
self.toolbar = NavigationToolbar(self.canvas, self)
|
||||
|
||||
self.vbox = QtGui.QVBoxLayout()
|
||||
self.vbox.addWidget(self.toolbar)
|
||||
self.vbox.addWidget(self.canvas)
|
||||
|
||||
self.setLayout(self.vbox)
|
||||
|
||||
def getFigure(self):
|
||||
return self.fig
|
||||
|
||||
def draw(self):
|
||||
self.canvas.draw()
|
Loading…
Reference in New Issue
Block a user