Skip to content

Commit

Permalink
Merged numerous updates from acq4:
Browse files Browse the repository at this point in the history
* Added HDF5 exporter
* CSV exporter gets (x,y,y,y) export mode
* Updates to SVG, Matplotlib exporter
* Console can filter exceptions by string
* Added tick context menu to GradientEditorItem
* Added export feature to imageview
* Parameter trees:
    - Option to save only user-editable values
    - Option to set visible title of parameters separately from name
    - Added experimental ParameterSystem for handling large systems of
        interdependent parameters
    - Auto-select editable portion of spinbox when editing
* Added Vector.__abs__
* Added replacement garbage collector for avoiding crashes on multithreaded Qt
* Fixed "illegal instruction" caused by closing file handle 7 on OSX
* configfile now reloads QtCore objects, Point, ColorMap, numpy arrays
* Avoid triggering recursion issues in exception handler
* Various bugfies and performance enhancements
  • Loading branch information
campagnola committed Aug 7, 2014
1 parent f9c85da commit ca3fbe2
Show file tree
Hide file tree
Showing 51 changed files with 1,912 additions and 540 deletions.
2 changes: 2 additions & 0 deletions Vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,7 @@ def angle(self, a):
# ang *= -1.
return ang * 180. / np.pi

def __abs__(self):
return Vector(abs(self.x()), abs(self.y()), abs(self.z()))


9 changes: 7 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,13 @@ def exit():
atexit._run_exitfuncs()

## close file handles
os.closerange(3, 4096) ## just guessing on the maximum descriptor count..

if sys.platform == 'darwin':
for fd in xrange(3, 4096):
if fd not in [7]: # trying to close 7 produces an illegal instruction on the Mac.
os.close(fd)
else:
os.closerange(3, 4096) ## just guessing on the maximum descriptor count..

os._exit(0)


Expand Down
18 changes: 11 additions & 7 deletions canvas/Canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ def __init__(self, parent=None, allowTransforms=True, hideCtrl=False, name=None)
self.ui.itemList.sigItemMoved.connect(self.treeItemMoved)
self.ui.itemList.itemSelectionChanged.connect(self.treeItemSelected)
self.ui.autoRangeBtn.clicked.connect(self.autoRange)
self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
self.ui.storePngBtn.clicked.connect(self.storePng)
#self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
#self.ui.storePngBtn.clicked.connect(self.storePng)
self.ui.redirectCheck.toggled.connect(self.updateRedirect)
self.ui.redirectCombo.currentIndexChanged.connect(self.updateRedirect)
self.multiSelectBox.sigRegionChanged.connect(self.multiSelectBoxChanged)
Expand All @@ -94,11 +94,13 @@ def __init__(self, parent=None, allowTransforms=True, hideCtrl=False, name=None)
self.ui.itemList.contextMenuEvent = self.itemListContextMenuEvent


def storeSvg(self):
self.ui.view.writeSvg()
#def storeSvg(self):
#from pyqtgraph.GraphicsScene.exportDialog import ExportDialog
#ex = ExportDialog(self.ui.view)
#ex.show()

def storePng(self):
self.ui.view.writeImage()
#def storePng(self):
#self.ui.view.writeImage()

def splitterMoved(self):
self.resizeEvent()
Expand Down Expand Up @@ -571,7 +573,9 @@ def itemListContextMenuEvent(self, ev):
self.menu.popup(ev.globalPos())

def removeClicked(self):
self.removeItem(self.menuItem)
#self.removeItem(self.menuItem)
for item in self.selectedItems():
self.removeItem(item)
self.menuItem = None
import gc
gc.collect()
Expand Down
28 changes: 7 additions & 21 deletions canvas/CanvasTemplate.ui
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,7 @@
<widget class="GraphicsView" name="view"/>
<widget class="QWidget" name="layoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QPushButton" name="storeSvgBtn">
<property name="text">
<string>Store SVG</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="storePngBtn">
<property name="text">
<string>Store PNG</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="autoRangeBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
Expand All @@ -55,7 +41,7 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
Expand All @@ -75,7 +61,7 @@
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<widget class="TreeWidget" name="itemList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
Expand All @@ -93,28 +79,28 @@
</column>
</widget>
</item>
<item row="11" column="0" colspan="2">
<item row="10" column="0" colspan="2">
<layout class="QGridLayout" name="ctrlLayout">
<property name="spacing">
<number>0</number>
</property>
</layout>
</item>
<item row="8" column="0">
<item row="7" column="0">
<widget class="QPushButton" name="resetTransformsBtn">
<property name="text">
<string>Reset Transforms</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="3" column="0">
<widget class="QPushButton" name="mirrorSelectionBtn">
<property name="text">
<string>Mirror Selection</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="3" column="1">
<widget class="QPushButton" name="reflectSelectionBtn">
<property name="text">
<string>MirrorXY</string>
Expand Down
53 changes: 18 additions & 35 deletions canvas/CanvasTemplate_pyqt.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file './pyqtgraph/canvas/CanvasTemplate.ui'
# Form implementation generated from reading ui file 'acq4/pyqtgraph/canvas/CanvasTemplate.ui'
#
# Created: Mon Dec 23 10:10:52 2013
# by: PyQt4 UI code generator 4.10
# Created: Thu Jan 2 11:13:07 2014
# by: PyQt4 UI code generator 4.9
#
# WARNING! All changes made in this file will be lost!

Expand All @@ -12,16 +12,7 @@
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s

try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
_fromUtf8 = lambda s: s

class Ui_Form(object):
def setupUi(self, Form):
Expand All @@ -41,20 +32,14 @@ def setupUi(self, Form):
self.gridLayout_2 = QtGui.QGridLayout(self.layoutWidget)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.storeSvgBtn = QtGui.QPushButton(self.layoutWidget)
self.storeSvgBtn.setObjectName(_fromUtf8("storeSvgBtn"))
self.gridLayout_2.addWidget(self.storeSvgBtn, 1, 0, 1, 1)
self.storePngBtn = QtGui.QPushButton(self.layoutWidget)
self.storePngBtn.setObjectName(_fromUtf8("storePngBtn"))
self.gridLayout_2.addWidget(self.storePngBtn, 1, 1, 1, 1)
self.autoRangeBtn = QtGui.QPushButton(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.autoRangeBtn.sizePolicy().hasHeightForWidth())
self.autoRangeBtn.setSizePolicy(sizePolicy)
self.autoRangeBtn.setObjectName(_fromUtf8("autoRangeBtn"))
self.gridLayout_2.addWidget(self.autoRangeBtn, 3, 0, 1, 2)
self.gridLayout_2.addWidget(self.autoRangeBtn, 2, 0, 1, 2)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
Expand All @@ -64,7 +49,7 @@ def setupUi(self, Form):
self.redirectCombo = CanvasCombo(self.layoutWidget)
self.redirectCombo.setObjectName(_fromUtf8("redirectCombo"))
self.horizontalLayout.addWidget(self.redirectCombo)
self.gridLayout_2.addLayout(self.horizontalLayout, 6, 0, 1, 2)
self.gridLayout_2.addLayout(self.horizontalLayout, 5, 0, 1, 2)
self.itemList = TreeWidget(self.layoutWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
Expand All @@ -74,35 +59,33 @@ def setupUi(self, Form):
self.itemList.setHeaderHidden(True)
self.itemList.setObjectName(_fromUtf8("itemList"))
self.itemList.headerItem().setText(0, _fromUtf8("1"))
self.gridLayout_2.addWidget(self.itemList, 7, 0, 1, 2)
self.gridLayout_2.addWidget(self.itemList, 6, 0, 1, 2)
self.ctrlLayout = QtGui.QGridLayout()
self.ctrlLayout.setSpacing(0)
self.ctrlLayout.setObjectName(_fromUtf8("ctrlLayout"))
self.gridLayout_2.addLayout(self.ctrlLayout, 11, 0, 1, 2)
self.gridLayout_2.addLayout(self.ctrlLayout, 10, 0, 1, 2)
self.resetTransformsBtn = QtGui.QPushButton(self.layoutWidget)
self.resetTransformsBtn.setObjectName(_fromUtf8("resetTransformsBtn"))
self.gridLayout_2.addWidget(self.resetTransformsBtn, 8, 0, 1, 1)
self.gridLayout_2.addWidget(self.resetTransformsBtn, 7, 0, 1, 1)
self.mirrorSelectionBtn = QtGui.QPushButton(self.layoutWidget)
self.mirrorSelectionBtn.setObjectName(_fromUtf8("mirrorSelectionBtn"))
self.gridLayout_2.addWidget(self.mirrorSelectionBtn, 4, 0, 1, 1)
self.gridLayout_2.addWidget(self.mirrorSelectionBtn, 3, 0, 1, 1)
self.reflectSelectionBtn = QtGui.QPushButton(self.layoutWidget)
self.reflectSelectionBtn.setObjectName(_fromUtf8("reflectSelectionBtn"))
self.gridLayout_2.addWidget(self.reflectSelectionBtn, 4, 1, 1, 1)
self.gridLayout_2.addWidget(self.reflectSelectionBtn, 3, 1, 1, 1)
self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1)

self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)

def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
self.storeSvgBtn.setText(_translate("Form", "Store SVG", None))
self.storePngBtn.setText(_translate("Form", "Store PNG", None))
self.autoRangeBtn.setText(_translate("Form", "Auto Range", None))
self.redirectCheck.setToolTip(_translate("Form", "Check to display all local items in a remote canvas.", None))
self.redirectCheck.setText(_translate("Form", "Redirect", None))
self.resetTransformsBtn.setText(_translate("Form", "Reset Transforms", None))
self.mirrorSelectionBtn.setText(_translate("Form", "Mirror Selection", None))
self.reflectSelectionBtn.setText(_translate("Form", "MirrorXY", None))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.autoRangeBtn.setText(QtGui.QApplication.translate("Form", "Auto Range", None, QtGui.QApplication.UnicodeUTF8))
self.redirectCheck.setToolTip(QtGui.QApplication.translate("Form", "Check to display all local items in a remote canvas.", None, QtGui.QApplication.UnicodeUTF8))
self.redirectCheck.setText(QtGui.QApplication.translate("Form", "Redirect", None, QtGui.QApplication.UnicodeUTF8))
self.resetTransformsBtn.setText(QtGui.QApplication.translate("Form", "Reset Transforms", None, QtGui.QApplication.UnicodeUTF8))
self.mirrorSelectionBtn.setText(QtGui.QApplication.translate("Form", "Mirror Selection", None, QtGui.QApplication.UnicodeUTF8))
self.reflectSelectionBtn.setText(QtGui.QApplication.translate("Form", "MirrorXY", None, QtGui.QApplication.UnicodeUTF8))

from ..widgets.TreeWidget import TreeWidget
from CanvasManager import CanvasCombo
Expand Down
5 changes: 4 additions & 1 deletion colormap.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,7 @@ def isMapTrivial(self):
else:
return np.all(self.color == np.array([[0,0,0,255], [255,255,255,255]]))


def __repr__(self):
pos = repr(self.pos).replace('\n', '')
color = repr(self.color).replace('\n', '')
return "ColorMap(%s, %s)" % (pos, color)
17 changes: 16 additions & 1 deletion configfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
GLOBAL_PATH = None # so not thread safe.
from . import units
from .python2_3 import asUnicode
from .Qt import QtCore
from .Point import Point
from .colormap import ColorMap
import numpy

class ParseError(Exception):
def __init__(self, message, lineNum, line, fileName=None):
Expand Down Expand Up @@ -46,7 +50,7 @@ def readConfigFile(fname):
fname2 = os.path.join(GLOBAL_PATH, fname)
if os.path.exists(fname2):
fname = fname2

GLOBAL_PATH = os.path.dirname(os.path.abspath(fname))

try:
Expand Down Expand Up @@ -135,6 +139,17 @@ def parseString(lines, start=0):
local = units.allUnits.copy()
local['OrderedDict'] = OrderedDict
local['readConfigFile'] = readConfigFile
local['Point'] = Point
local['QtCore'] = QtCore
local['ColorMap'] = ColorMap
# Needed for reconstructing numpy arrays
local['array'] = numpy.array
for dtype in ['int8', 'uint8',
'int16', 'uint16', 'float16',
'int32', 'uint32', 'float32',
'int64', 'uint64', 'float64']:
local[dtype] = getattr(numpy, dtype)

if len(k) < 1:
raise ParseError('Missing name preceding colon', ln+1, l)
if k[0] == '(' and k[-1] == ')': ## If the key looks like a tuple, try evaluating it.
Expand Down
11 changes: 11 additions & 0 deletions console/Console.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,17 @@ def checkException(self, excType, exc, tb):
filename = tb.tb_frame.f_code.co_filename
function = tb.tb_frame.f_code.co_name

filterStr = str(self.ui.filterText.text())
if filterStr != '':
if isinstance(exc, Exception):
msg = exc.message
elif isinstance(exc, basestring):
msg = exc
else:
msg = repr(exc)
match = re.search(filterStr, "%s:%s:%s" % (filename, function, msg))
return match is not None

## Go through a list of common exception points we like to ignore:
if excType is GeneratorExit or excType is StopIteration:
return False
Expand Down
Loading

0 comments on commit ca3fbe2

Please sign in to comment.