Minor updates for exporting

- curves enable antialiasing when exporting to image
  - plotitems hide button during export
This commit is contained in:
Luke Campagnola 2012-03-23 02:41:10 -04:00
parent 7c94b5a702
commit b78662c33e
13 changed files with 245 additions and 41 deletions

View File

@ -59,12 +59,12 @@ class GraphicsScene(QtGui.QGraphicsScene):
move in a drag.
"""
_addressCache = weakref.WeakValueDictionary()
sigMouseHover = QtCore.Signal(object) ## emits a list of objects hovered over
sigMouseMoved = QtCore.Signal(object) ## emits position of mouse on every move
sigMouseClicked = QtCore.Signal(object) ## emitted when MouseClickEvent is not accepted by any items under the click.
_addressCache = weakref.WeakValueDictionary()
ExportDirectory = None
@classmethod

View File

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'exportDialogTemplate.ui'
#
# Created: Sat Mar 10 17:54:53 2012
# Created: Thu Mar 22 13:13:06 2012
# by: PyQt4 UI code generator 4.8.5
#
# WARNING! All changes made in this file will be lost!
@ -18,7 +18,7 @@ class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(241, 367)
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Export", None, QtGui.QApplication.UnicodeUTF8))
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
<string>Export</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="spacing">

View File

@ -75,8 +75,74 @@ class Exporter(object):
else:
return self.item.mapRectToDevice(self.item.boundingRect())
def setExportMode(self, export, opts=None):
"""
Call setExportMode(export, opts) on all items that will
be painted during the export. This informs the item
that it is about to be painted for export, allowing it to
alter its appearance temporarily
*export* - bool; must be True before exporting and False afterward
*opts* - dict; common parameters are 'antialias' and 'background'
"""
if opts is None:
opts = {}
for item in self.getPaintItems():
if hasattr(item, 'setExportMode'):
item.setExportMode(export, opts)
def getPaintItems(self, root=None):
"""Return a list of all items that should be painted in the correct order."""
if root is None:
root = self.item
preItems = []
postItems = []
if isinstance(root, QtGui.QGraphicsScene):
childs = [i for i in root.items() if i.parentItem() is None]
rootItem = []
else:
childs = root.childItems()
rootItem = [root]
childs.sort(lambda a,b: cmp(a.zValue(), b.zValue()))
while len(childs) > 0:
ch = childs.pop(0)
tree = self.getPaintItems(ch)
if int(ch.flags() & ch.ItemStacksBehindParent) > 0 or (ch.zValue() < 0 and int(ch.flags() & ch.ItemNegativeZStacksBehindParent) > 0):
preItems.extend(tree)
else:
postItems.extend(tree)
return preItems + rootItem + postItems
def render(self, painter, sourcRect, targetRect, item=None)
#if item is None:
#item = self.item
#preItems = []
#postItems = []
#if isinstance(item, QtGui.QGraphicsScene):
#childs = [i for i in item.items() if i.parentItem() is None]
#rootItem = []
#else:
#childs = item.childItems()
#rootItem = [item]
#childs.sort(lambda a,b: cmp(a.zValue(), b.zValue()))
#while len(childs) > 0:
#ch = childs.pop(0)
#if int(ch.flags() & ch.ItemStacksBehindParent) > 0 or (ch.zValue() < 0 and int(ch.flags() & ch.ItemNegativeZStacksBehindParent) > 0):
#preItems.extend(tree)
#else:
#postItems.extend(tree)
#for ch in preItems:
#self.render(painter, sourceRect, targetRect, item=ch)
### paint root here
#for ch in postItems:
#self.render(painter, sourceRect, targetRect, item=ch)
self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect))
#def writePs(self, fileName=None, item=None):
#if fileName is None:

View File

@ -57,6 +57,12 @@ class ImageExporter(Exporter):
bg[:,:,3] = color.alpha()
self.png = pg.makeQImage(bg, alpha=True)
painter = QtGui.QPainter(self.png)
self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect)
try:
self.setExportMode(True, {'antialias': self.params['antialias'], 'background': self.params['background']})
self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect)
finally:
self.setExportMode(False)
self.png.save(fileName)
painter.end()
painter.end()

View File

@ -0,0 +1,59 @@
from Exporter import Exporter
from pyqtgraph.parametertree import Parameter
from pyqtgraph.Qt import QtGui, QtCore, QtSvg
import re
#__all__ = ['PrintExporter']
__all__ = [] ## Printer is disabled for now--does not work very well.
class PrintExporter(Exporter):
Name = "Printer"
def __init__(self, item):
Exporter.__init__(self, item)
tr = self.getTargetRect()
self.params = Parameter(name='params', type='group', children=[
{'name': 'width', 'type': 'float', 'value': 0.1, 'limits': (0, None), 'suffix': 'm', 'siPrefix': True},
{'name': 'height', 'type': 'float', 'value': (0.1 * tr.height()) / tr.width(), 'limits': (0, None), 'suffix': 'm', 'siPrefix': True},
])
self.params.param('width').sigValueChanged.connect(self.widthChanged)
self.params.param('height').sigValueChanged.connect(self.heightChanged)
def widthChanged(self):
sr = self.getSourceRect()
ar = sr.height() / sr.width()
self.params.param('height').setValue(self.params['width'] * ar, blockSignal=self.heightChanged)
def heightChanged(self):
sr = self.getSourceRect()
ar = sr.width() / sr.height()
self.params.param('width').setValue(self.params['height'] * ar, blockSignal=self.widthChanged)
def parameters(self):
return self.params
def export(self, fileName=None):
printer = QtGui.QPrinter(QtGui.QPrinter.HighResolution)
dialog = QtGui.QPrintDialog(printer)
dialog.setWindowTitle("Print Document")
if dialog.exec_() != QtGui.QDialog.Accepted:
return;
#self.svg.setSize(QtCore.QSize(100,100))
#self.svg.setResolution(600)
res = printer.resolution()
rect = printer.pageRect()
center = rect.center()
h = self.params['height'] * res * 100. / 2.54
w = self.params['width'] * res * 100. / 2.54
x = center.x() - w/2.
y = center.y() - h/2.
targetRect = QtCore.QRect(x, y, w, h)
sourceRect = self.getSourceRect()
painter = QtGui.QPainter(printer)
try:
self.setExportMode(True)
self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect)
finally:
self.setExportMode(False)
painter.end()

View File

@ -42,7 +42,11 @@ class SVGExporter(Exporter):
targetRect = QtCore.QRect(0, 0, self.params['width'], self.params['height'])
sourceRect = self.getSourceRect()
painter = QtGui.QPainter(self.svg)
self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect)
try:
self.setExportMode(True)
self.render(painter, QtCore.QRectF(targetRect), sourceRect)
finally:
self.setExportMode(False)
painter.end()
## Workaround to set pen widths correctly

View File

@ -1,6 +1,24 @@
from SVGExporter import *
from ImageExporter import *
Exporters = [SVGExporter, ImageExporter]
Exporters = []
import os, sys
d = os.path.split(__file__)[0]
files = []
for f in os.listdir(d):
if os.path.isdir(os.path.join(d, f)):
files.append(f)
elif f[-3:] == '.py' and f not in ['__init__.py', 'Exporter.py']:
files.append(f[:-3])
for modName in files:
mod = __import__(modName, globals(), locals(), fromlist=['*'])
if hasattr(mod, '__all__'):
names = mod.__all__
else:
names = [n for n in dir(mod) if n[0] != '_']
for k in names:
if hasattr(mod, k):
Exporters.append(getattr(mod, k))
def listExporters():
return Exporters[:]

View File

@ -261,6 +261,9 @@ class AxisItem(GraphicsWidget):
def drawPicture(self, p):
p.setRenderHint(p.Antialiasing, False)
p.setRenderHint(p.TextAntialiasing, True)
prof = debug.Profiler("AxisItem.paint", disabled=True)
p.setPen(self.pen)

View File

@ -27,6 +27,8 @@ class PlotCurveItem(GraphicsObject):
self.clear()
self.path = None
self.fillPath = None
self.exportOpts = False
self.antialias = False
if y is not None:
self.updateData(y, x)
@ -364,6 +366,14 @@ class PlotCurveItem(GraphicsObject):
#pen.setColor(c)
##pen.setCosmetic(True)
if self.exportOpts is not False:
aa = self.exportOpts['antialias']
else:
aa = self.antialias
p.setRenderHint(p.Antialiasing, aa)
if sp is not None:
p.setPen(sp)
p.drawPath(path)
@ -410,7 +420,13 @@ class PlotCurveItem(GraphicsObject):
ev.accept()
self.sigClicked.emit(self)
def setExportMode(self, export, opts):
if export:
self.exportOpts = opts
if 'antialias' not in opts:
self.exportOpts['antialias'] = True
else:
self.exportOpts = False
class ROIPlotItem(PlotCurveItem):
"""Plot curve that monitors an ROI and image for changes to automatically replot."""

View File

@ -64,6 +64,20 @@ class PlotItem(GraphicsWidget):
managers = {}
def __init__(self, parent=None, name=None, labels=None, title=None, **kargs):
"""
Create a new PlotItem. All arguments are optional.
Any extra keyword arguments are passed to PlotItem.plot().
Arguments:
*title* - Title to display at the top of the item. Html is allowed.
*labels* - A dictionary specifying the axis labels to display.
{'left': (args), 'bottom': (args), ...}
The name of each axis and the corresponding arguments are passed to PlotItem.setLabel()
Optionally, PlotItem my also be initialized with the keyword arguments left,
right, top, or bottom to achieve the same effect.
*name* - Registers a name for this view so that others may link to it
"""
GraphicsWidget.__init__(self, parent)
self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
@ -250,12 +264,16 @@ class PlotItem(GraphicsWidget):
#if name is not None:
#self.registerPlot(name)
if labels is not None:
for k in labels:
if isinstance(labels[k], basestring):
labels[k] = (labels[k],)
self.setLabel(k, *labels[k])
if labels is None:
labels = {}
for label in self.scales.keys():
if label in kargs:
labels[label] = kargs[label]
del kargs[label]
for k in labels:
if isinstance(labels[k], basestring):
labels[k] = (labels[k],)
self.setLabel(k, *labels[k])
if title is not None:
self.setTitle(title)
@ -263,7 +281,7 @@ class PlotItem(GraphicsWidget):
if len(kargs) > 0:
self.plot(**kargs)
self.enableAutoRange()
#self.enableAutoRange()
def implements(self, interface=None):
return interface in ['ViewBoxWrapper']
@ -365,6 +383,8 @@ class PlotItem(GraphicsWidget):
#print " Referrers are:", refs
#raise
def updateGrid(self, *args):
g = self.ctrl.gridGroup.isChecked()
if g:
@ -1313,18 +1333,24 @@ class PlotItem(GraphicsWidget):
return c
def saveSvgClicked(self):
self.writeSvg()
#def saveSvgClicked(self):
#self.writeSvg()
def saveSvgCurvesClicked(self):
self.writeSvgCurves()
#def saveSvgCurvesClicked(self):
#self.writeSvgCurves()
def saveImgClicked(self):
self.writeImage()
#def saveImgClicked(self):
#self.writeImage()
def saveCsvClicked(self):
self.writeCsv()
#def saveCsvClicked(self):
#self.writeCsv()
def setExportMode(self, export, opts):
if export:
self.autoBtn.hide()
else:
self.autoBtn.show()
#class PlotWidgetManager(QtCore.QObject):

View File

@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'axisCtrlTemplate.ui'
#
# Created: Fri Jan 20 12:41:24 2012
# by: PyQt4 UI code generator 4.8.3
# Created: Thu Mar 22 13:13:14 2012
# by: PyQt4 UI code generator 4.8.5
#
# WARNING! All changes made in this file will be lost!
@ -19,41 +19,51 @@ class Ui_Form(object):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(182, 120)
Form.setMaximumSize(QtCore.QSize(200, 16777215))
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.mouseCheck = QtGui.QCheckBox(Form)
self.mouseCheck.setText(QtGui.QApplication.translate("Form", "Mouse Enabled", None, QtGui.QApplication.UnicodeUTF8))
self.mouseCheck.setChecked(True)
self.mouseCheck.setObjectName(_fromUtf8("mouseCheck"))
self.gridLayout.addWidget(self.mouseCheck, 0, 1, 1, 2)
self.manualRadio = QtGui.QRadioButton(Form)
self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8))
self.manualRadio.setObjectName(_fromUtf8("manualRadio"))
self.gridLayout.addWidget(self.manualRadio, 1, 0, 1, 1)
self.minText = QtGui.QLineEdit(Form)
self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.minText.setObjectName(_fromUtf8("minText"))
self.gridLayout.addWidget(self.minText, 1, 1, 1, 1)
self.maxText = QtGui.QLineEdit(Form)
self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.maxText.setObjectName(_fromUtf8("maxText"))
self.gridLayout.addWidget(self.maxText, 1, 2, 1, 1)
self.autoRadio = QtGui.QRadioButton(Form)
self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8))
self.autoRadio.setChecked(True)
self.autoRadio.setObjectName(_fromUtf8("autoRadio"))
self.gridLayout.addWidget(self.autoRadio, 2, 0, 1, 1)
self.autoPercentSpin = QtGui.QSpinBox(Form)
self.autoPercentSpin.setEnabled(True)
self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8))
self.autoPercentSpin.setMinimum(1)
self.autoPercentSpin.setMaximum(100)
self.autoPercentSpin.setSingleStep(1)
self.autoPercentSpin.setProperty(_fromUtf8("value"), 100)
self.autoPercentSpin.setProperty("value", 100)
self.autoPercentSpin.setObjectName(_fromUtf8("autoPercentSpin"))
self.gridLayout.addWidget(self.autoPercentSpin, 2, 1, 1, 2)
self.autoPanCheck = QtGui.QCheckBox(Form)
self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8))
self.autoPanCheck.setObjectName(_fromUtf8("autoPanCheck"))
self.gridLayout.addWidget(self.autoPanCheck, 3, 1, 1, 2)
self.linkCombo = QtGui.QComboBox(Form)
self.linkCombo.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
self.linkCombo.setObjectName(_fromUtf8("linkCombo"))
self.gridLayout.addWidget(self.linkCombo, 4, 1, 1, 2)
self.label = QtGui.QLabel(Form)
self.label.setText(QtGui.QApplication.translate("Form", "Link Axis:", None, QtGui.QApplication.UnicodeUTF8))
self.label.setObjectName(_fromUtf8("label"))
self.gridLayout.addWidget(self.label, 4, 0, 1, 1)
@ -61,13 +71,5 @@ class Ui_Form(object):
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.mouseCheck.setText(QtGui.QApplication.translate("Form", "Mouse Enabled", None, QtGui.QApplication.UnicodeUTF8))
self.manualRadio.setText(QtGui.QApplication.translate("Form", "Manual", None, QtGui.QApplication.UnicodeUTF8))
self.minText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.maxText.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8))
self.autoRadio.setText(QtGui.QApplication.translate("Form", "Auto", None, QtGui.QApplication.UnicodeUTF8))
self.autoPercentSpin.setSuffix(QtGui.QApplication.translate("Form", "%", None, QtGui.QApplication.UnicodeUTF8))
self.autoPanCheck.setText(QtGui.QApplication.translate("Form", "Auto Pan Only", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("Form", "Link Axis:", None, QtGui.QApplication.UnicodeUTF8))
pass

View File

@ -94,7 +94,11 @@
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="linkCombo"/>
<widget class="QComboBox" name="linkCombo">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label">