Added better API for controlling antialiasing in plots
PlotItem auto-range button is now hidden by default; only appears for plots that are not already auto-ranged and have mouse hover.
This commit is contained in:
parent
ef9d730d89
commit
a157d9c4fa
|
@ -18,7 +18,7 @@ app = QtGui.QApplication([])
|
||||||
#mw.resize(800,800)
|
#mw.resize(800,800)
|
||||||
|
|
||||||
win = pg.GraphicsWindow(title="Basic plotting examples")
|
win = pg.GraphicsWindow(title="Basic plotting examples")
|
||||||
win.resize(800,600)
|
win.resize(1000,600)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from .GraphicsObject import GraphicsObject
|
||||||
import pyqtgraph.functions as fn
|
import pyqtgraph.functions as fn
|
||||||
from pyqtgraph import debug
|
from pyqtgraph import debug
|
||||||
from pyqtgraph.Point import Point
|
from pyqtgraph.Point import Point
|
||||||
|
import pyqtgraph as pg
|
||||||
import struct, sys
|
import struct, sys
|
||||||
|
|
||||||
__all__ = ['PlotCurveItem']
|
__all__ = ['PlotCurveItem']
|
||||||
|
@ -52,7 +53,6 @@ class PlotCurveItem(GraphicsObject):
|
||||||
self.path = None
|
self.path = None
|
||||||
self.fillPath = None
|
self.fillPath = None
|
||||||
self.exportOpts = False
|
self.exportOpts = False
|
||||||
self.antialias = False
|
|
||||||
|
|
||||||
|
|
||||||
## this is disastrous for performance.
|
## this is disastrous for performance.
|
||||||
|
@ -65,7 +65,8 @@ class PlotCurveItem(GraphicsObject):
|
||||||
'fillLevel': None,
|
'fillLevel': None,
|
||||||
'brush': None,
|
'brush': None,
|
||||||
'stepMode': False,
|
'stepMode': False,
|
||||||
'name': None
|
'name': None,
|
||||||
|
'antialias': pg.getConfigOption('antialias'),
|
||||||
}
|
}
|
||||||
self.setClickable(kargs.get('clickable', False))
|
self.setClickable(kargs.get('clickable', False))
|
||||||
self.setData(*args, **kargs)
|
self.setData(*args, **kargs)
|
||||||
|
@ -168,7 +169,7 @@ class PlotCurveItem(GraphicsObject):
|
||||||
|
|
||||||
def setData(self, *args, **kargs):
|
def setData(self, *args, **kargs):
|
||||||
"""
|
"""
|
||||||
============== =======================================================
|
============== ========================================================
|
||||||
**Arguments:**
|
**Arguments:**
|
||||||
x, y (numpy arrays) Data to show
|
x, y (numpy arrays) Data to show
|
||||||
pen Pen to use when drawing. Any single argument accepted by
|
pen Pen to use when drawing. Any single argument accepted by
|
||||||
|
@ -181,7 +182,9 @@ class PlotCurveItem(GraphicsObject):
|
||||||
*fillLevel*
|
*fillLevel*
|
||||||
brush QBrush to use when filling. Any single argument accepted
|
brush QBrush to use when filling. Any single argument accepted
|
||||||
by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed.
|
by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed.
|
||||||
============== =======================================================
|
antialias (bool) Whether to use antialiasing when drawing. This
|
||||||
|
is disabled by default because it decreases performance.
|
||||||
|
============== ========================================================
|
||||||
|
|
||||||
If non-keyword arguments are used, they will be interpreted as
|
If non-keyword arguments are used, they will be interpreted as
|
||||||
setData(y) for a single argument and setData(x, y) for two
|
setData(y) for a single argument and setData(x, y) for two
|
||||||
|
@ -250,6 +253,8 @@ class PlotCurveItem(GraphicsObject):
|
||||||
self.setFillLevel(kargs['fillLevel'])
|
self.setFillLevel(kargs['fillLevel'])
|
||||||
if 'brush' in kargs:
|
if 'brush' in kargs:
|
||||||
self.setBrush(kargs['brush'])
|
self.setBrush(kargs['brush'])
|
||||||
|
if 'antialias' in kargs:
|
||||||
|
self.opts['antialias'] = kargs['antialias']
|
||||||
|
|
||||||
|
|
||||||
prof.mark('set')
|
prof.mark('set')
|
||||||
|
@ -398,6 +403,14 @@ class PlotCurveItem(GraphicsObject):
|
||||||
|
|
||||||
path = self.path
|
path = self.path
|
||||||
prof.mark('generate path')
|
prof.mark('generate path')
|
||||||
|
|
||||||
|
if self.exportOpts is not False:
|
||||||
|
aa = self.exportOpts['antialias']
|
||||||
|
else:
|
||||||
|
aa = self.opts['antialias']
|
||||||
|
|
||||||
|
p.setRenderHint(p.Antialiasing, aa)
|
||||||
|
|
||||||
|
|
||||||
if self.opts['brush'] is not None and self.opts['fillLevel'] is not None:
|
if self.opts['brush'] is not None and self.opts['fillLevel'] is not None:
|
||||||
if self.fillPath is None:
|
if self.fillPath is None:
|
||||||
|
@ -426,12 +439,6 @@ class PlotCurveItem(GraphicsObject):
|
||||||
#pen.setColor(c)
|
#pen.setColor(c)
|
||||||
##pen.setCosmetic(True)
|
##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:
|
if sp is not None:
|
||||||
|
|
|
@ -7,6 +7,7 @@ import numpy as np
|
||||||
import scipy
|
import scipy
|
||||||
import pyqtgraph.functions as fn
|
import pyqtgraph.functions as fn
|
||||||
import pyqtgraph.debug as debug
|
import pyqtgraph.debug as debug
|
||||||
|
import pyqtgraph as pg
|
||||||
|
|
||||||
class PlotDataItem(GraphicsObject):
|
class PlotDataItem(GraphicsObject):
|
||||||
"""
|
"""
|
||||||
|
@ -84,6 +85,9 @@ class PlotDataItem(GraphicsObject):
|
||||||
**Optimization keyword arguments:**
|
**Optimization keyword arguments:**
|
||||||
|
|
||||||
========== =====================================================================
|
========== =====================================================================
|
||||||
|
antialias (bool) By default, antialiasing is disabled to improve performance.
|
||||||
|
Note that in some cases (in particluar, when pxMode=True), points
|
||||||
|
will be rendered antialiased even if this is set to False.
|
||||||
identical *deprecated*
|
identical *deprecated*
|
||||||
decimate (int) sub-sample data by selecting every nth sample before plotting
|
decimate (int) sub-sample data by selecting every nth sample before plotting
|
||||||
========== =====================================================================
|
========== =====================================================================
|
||||||
|
@ -130,6 +134,7 @@ class PlotDataItem(GraphicsObject):
|
||||||
'symbolBrush': (50, 50, 150),
|
'symbolBrush': (50, 50, 150),
|
||||||
'pxMode': True,
|
'pxMode': True,
|
||||||
|
|
||||||
|
'antialias': pg.getConfigOption('antialias'),
|
||||||
'pointMode': None,
|
'pointMode': None,
|
||||||
|
|
||||||
'data': None,
|
'data': None,
|
||||||
|
@ -379,11 +384,11 @@ class PlotDataItem(GraphicsObject):
|
||||||
#c.scene().removeItem(c)
|
#c.scene().removeItem(c)
|
||||||
|
|
||||||
curveArgs = {}
|
curveArgs = {}
|
||||||
for k,v in [('pen','pen'), ('shadowPen','shadowPen'), ('fillLevel','fillLevel'), ('fillBrush', 'brush')]:
|
for k,v in [('pen','pen'), ('shadowPen','shadowPen'), ('fillLevel','fillLevel'), ('fillBrush', 'brush'), ('antialias', 'antialias')]:
|
||||||
curveArgs[v] = self.opts[k]
|
curveArgs[v] = self.opts[k]
|
||||||
|
|
||||||
scatterArgs = {}
|
scatterArgs = {}
|
||||||
for k,v in [('symbolPen','pen'), ('symbolBrush','brush'), ('symbol','symbol'), ('symbolSize', 'size'), ('data', 'data'), ('pxMode', 'pxMode')]:
|
for k,v in [('symbolPen','pen'), ('symbolBrush','brush'), ('symbol','symbol'), ('symbolSize', 'size'), ('data', 'data'), ('pxMode', 'pxMode'), ('antialias', 'antialias')]:
|
||||||
if k in self.opts:
|
if k in self.opts:
|
||||||
scatterArgs[v] = self.opts[k]
|
scatterArgs[v] = self.opts[k]
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,9 @@ class PlotItem(GraphicsWidget):
|
||||||
self.autoBtn = ButtonItem(pyqtgraph.pixmaps.getPixmap('auto'), 14, self)
|
self.autoBtn = ButtonItem(pyqtgraph.pixmaps.getPixmap('auto'), 14, self)
|
||||||
self.autoBtn.mode = 'auto'
|
self.autoBtn.mode = 'auto'
|
||||||
self.autoBtn.clicked.connect(self.autoBtnClicked)
|
self.autoBtn.clicked.connect(self.autoBtnClicked)
|
||||||
|
#self.autoBtn.hide()
|
||||||
|
self.buttonsHidden = False ## whether the user has requested buttons to be hidden
|
||||||
|
self.mouseHovering = False
|
||||||
|
|
||||||
self.layout = QtGui.QGraphicsGridLayout()
|
self.layout = QtGui.QGraphicsGridLayout()
|
||||||
self.layout.setContentsMargins(1,1,1,1)
|
self.layout.setContentsMargins(1,1,1,1)
|
||||||
|
@ -141,6 +144,7 @@ class PlotItem(GraphicsWidget):
|
||||||
if viewBox is None:
|
if viewBox is None:
|
||||||
viewBox = ViewBox()
|
viewBox = ViewBox()
|
||||||
self.vb = viewBox
|
self.vb = viewBox
|
||||||
|
self.vb.sigStateChanged.connect(self.viewStateChanged)
|
||||||
self.setMenuEnabled(enableMenu, enableMenu) ## en/disable plotitem and viewbox menus
|
self.setMenuEnabled(enableMenu, enableMenu) ## en/disable plotitem and viewbox menus
|
||||||
|
|
||||||
if name is not None:
|
if name is not None:
|
||||||
|
@ -476,9 +480,13 @@ class PlotItem(GraphicsWidget):
|
||||||
def autoBtnClicked(self):
|
def autoBtnClicked(self):
|
||||||
if self.autoBtn.mode == 'auto':
|
if self.autoBtn.mode == 'auto':
|
||||||
self.enableAutoRange()
|
self.enableAutoRange()
|
||||||
|
self.autoBtn.hide()
|
||||||
else:
|
else:
|
||||||
self.disableAutoRange()
|
self.disableAutoRange()
|
||||||
|
|
||||||
|
def viewStateChanged(self):
|
||||||
|
self.updateButtons()
|
||||||
|
|
||||||
def enableAutoScale(self):
|
def enableAutoScale(self):
|
||||||
"""
|
"""
|
||||||
Enable auto-scaling. The plot will continuously scale to fit the boundaries of its data.
|
Enable auto-scaling. The plot will continuously scale to fit the boundaries of its data.
|
||||||
|
@ -1003,7 +1011,14 @@ class PlotItem(GraphicsWidget):
|
||||||
def menuEnabled(self):
|
def menuEnabled(self):
|
||||||
return self._menuEnabled
|
return self._menuEnabled
|
||||||
|
|
||||||
|
def hoverEvent(self, ev):
|
||||||
|
if ev.enter:
|
||||||
|
self.mouseHovering = True
|
||||||
|
if ev.exit:
|
||||||
|
self.mouseHovering = False
|
||||||
|
|
||||||
|
self.updateButtons()
|
||||||
|
|
||||||
|
|
||||||
def getLabel(self, key):
|
def getLabel(self, key):
|
||||||
pass
|
pass
|
||||||
|
@ -1082,8 +1097,20 @@ class PlotItem(GraphicsWidget):
|
||||||
def hideButtons(self):
|
def hideButtons(self):
|
||||||
"""Causes auto-scale button ('A' in lower-left corner) to be hidden for this PlotItem"""
|
"""Causes auto-scale button ('A' in lower-left corner) to be hidden for this PlotItem"""
|
||||||
#self.ctrlBtn.hide()
|
#self.ctrlBtn.hide()
|
||||||
self.autoBtn.hide()
|
self.buttonsHidden = True
|
||||||
|
self.updateButtons()
|
||||||
|
|
||||||
|
def showButtons(self):
|
||||||
|
"""Causes auto-scale button ('A' in lower-left corner) to be visible for this PlotItem"""
|
||||||
|
#self.ctrlBtn.hide()
|
||||||
|
self.buttonsHidden = False
|
||||||
|
self.updateButtons()
|
||||||
|
|
||||||
|
def updateButtons(self):
|
||||||
|
if self.mouseHovering and not self.buttonsHidden and not all(self.vb.autoRangeEnabled()):
|
||||||
|
self.autoBtn.show()
|
||||||
|
else:
|
||||||
|
self.autoBtn.hide()
|
||||||
|
|
||||||
def _plotArray(self, arr, x=None, **kargs):
|
def _plotArray(self, arr, x=None, **kargs):
|
||||||
if arr.ndim != 1:
|
if arr.ndim != 1:
|
||||||
|
|
|
@ -8,6 +8,7 @@ import scipy.stats
|
||||||
import weakref
|
import weakref
|
||||||
import pyqtgraph.debug as debug
|
import pyqtgraph.debug as debug
|
||||||
from pyqtgraph.pgcollections import OrderedDict
|
from pyqtgraph.pgcollections import OrderedDict
|
||||||
|
import pyqtgraph as pg
|
||||||
#import pyqtgraph as pg
|
#import pyqtgraph as pg
|
||||||
|
|
||||||
__all__ = ['ScatterPlotItem', 'SpotItem']
|
__all__ = ['ScatterPlotItem', 'SpotItem']
|
||||||
|
@ -233,7 +234,12 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
self.bounds = [None, None] ## caches data bounds
|
self.bounds = [None, None] ## caches data bounds
|
||||||
self._maxSpotWidth = 0 ## maximum size of the scale-variant portion of all spots
|
self._maxSpotWidth = 0 ## maximum size of the scale-variant portion of all spots
|
||||||
self._maxSpotPxWidth = 0 ## maximum size of the scale-invariant portion of all spots
|
self._maxSpotPxWidth = 0 ## maximum size of the scale-invariant portion of all spots
|
||||||
self.opts = {'pxMode': True, 'useCache': True, 'exportMode': False} ## If useCache is False, symbols are re-drawn on every paint.
|
self.opts = {
|
||||||
|
'pxMode': True,
|
||||||
|
'useCache': True, ## If useCache is False, symbols are re-drawn on every paint.
|
||||||
|
'antialias': pg.getConfigOption('antialias'),
|
||||||
|
}
|
||||||
|
self.exportOpts = False
|
||||||
|
|
||||||
self.setPen(200,200,200, update=False)
|
self.setPen(200,200,200, update=False)
|
||||||
self.setBrush(100,100,150, update=False)
|
self.setBrush(100,100,150, update=False)
|
||||||
|
@ -278,6 +284,9 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
it is in the item's local coordinate system.
|
it is in the item's local coordinate system.
|
||||||
*data* a list of python objects used to uniquely identify each spot.
|
*data* a list of python objects used to uniquely identify each spot.
|
||||||
*identical* *Deprecated*. This functionality is handled automatically now.
|
*identical* *Deprecated*. This functionality is handled automatically now.
|
||||||
|
*antialias* Whether to draw symbols with antialiasing. Note that if pxMode is True, symbols are
|
||||||
|
always rendered with antialiasing (since the rendered symbols can be cached, this
|
||||||
|
incurs very little performance cost)
|
||||||
====================== ===============================================================================================
|
====================== ===============================================================================================
|
||||||
"""
|
"""
|
||||||
oldData = self.data ## this causes cached pixmaps to be preserved while new data is registered.
|
oldData = self.data ## this causes cached pixmaps to be preserved while new data is registered.
|
||||||
|
@ -369,6 +378,8 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
|
|
||||||
if 'pxMode' in kargs:
|
if 'pxMode' in kargs:
|
||||||
self.setPxMode(kargs['pxMode'])
|
self.setPxMode(kargs['pxMode'])
|
||||||
|
if 'antialias' in kargs:
|
||||||
|
self.opts['antialias'] = kargs['antialias']
|
||||||
|
|
||||||
## Set any extra parameters provided in keyword arguments
|
## Set any extra parameters provided in keyword arguments
|
||||||
for k in ['pen', 'brush', 'symbol', 'size']:
|
for k in ['pen', 'brush', 'symbol', 'size']:
|
||||||
|
@ -378,7 +389,7 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
|
|
||||||
if 'data' in kargs:
|
if 'data' in kargs:
|
||||||
self.setPointData(kargs['data'], dataSet=newData)
|
self.setPointData(kargs['data'], dataSet=newData)
|
||||||
|
|
||||||
self.prepareGeometryChange()
|
self.prepareGeometryChange()
|
||||||
self.bounds = [None, None]
|
self.bounds = [None, None]
|
||||||
self.invalidate()
|
self.invalidate()
|
||||||
|
@ -664,8 +675,13 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
rect = QtCore.QRectF(y, x, h, w)
|
rect = QtCore.QRectF(y, x, h, w)
|
||||||
self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect))
|
self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect))
|
||||||
|
|
||||||
def setExportMode(self, enabled, opts):
|
def setExportMode(self, export, opts):
|
||||||
self.opts['exportMode'] = enabled
|
if export:
|
||||||
|
self.exportOpts = opts
|
||||||
|
if 'antialias' not in opts:
|
||||||
|
self.exportOpts['antialias'] = True
|
||||||
|
else:
|
||||||
|
self.exportOpts = False
|
||||||
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
def paint(self, p, *args):
|
||||||
|
@ -685,9 +701,15 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
|
|
||||||
p.resetTransform()
|
p.resetTransform()
|
||||||
|
|
||||||
if not USE_PYSIDE and self.opts['useCache'] and self.opts['exportMode'] is False:
|
if not USE_PYSIDE and self.opts['useCache'] and self.exportOpts is False:
|
||||||
p.drawPixmapFragments(self.fragments, atlas)
|
p.drawPixmapFragments(self.fragments, atlas)
|
||||||
else:
|
else:
|
||||||
|
if self.exportOpts is not False:
|
||||||
|
aa = self.exportOpts['antialias']
|
||||||
|
else:
|
||||||
|
aa = self.opts['antialias']
|
||||||
|
p.setRenderHint(p.Antialiasing, aa)
|
||||||
|
|
||||||
for i in range(len(self.data)):
|
for i in range(len(self.data)):
|
||||||
rec = self.data[i]
|
rec = self.data[i]
|
||||||
frag = self.fragments[i]
|
frag = self.fragments[i]
|
||||||
|
@ -705,6 +727,11 @@ class ScatterPlotItem(GraphicsObject):
|
||||||
drawSymbol(p2, *self.getSpotOpts(rec))
|
drawSymbol(p2, *self.getSpotOpts(rec))
|
||||||
p2.end()
|
p2.end()
|
||||||
|
|
||||||
|
if self.exportOpts is not False:
|
||||||
|
aa = self.exportOpts['antialias']
|
||||||
|
else:
|
||||||
|
aa = self.opts['antialias']
|
||||||
|
p.setRenderHint(p.Antialiasing, aa)
|
||||||
self.picture.play(p)
|
self.picture.play(p)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue