New features for LegendItem:
- Can be anchored to parent item at any location - Support for filled plot styles - Automatically resizes to fit contents - PlotItem can auto-generate legend
This commit is contained in:
parent
e5f383fbb5
commit
9b41c90034
@ -6,13 +6,14 @@ from pyqtgraph.Qt import QtCore, QtGui
|
||||
|
||||
plt = pg.plot()
|
||||
|
||||
l = pg.LegendItem((100,60), (60,10)) # args are (size, position)
|
||||
l.setParentItem(plt.graphicsItem()) # Note we do NOT call plt.addItem in this case
|
||||
plt.addLegend()
|
||||
#l = pg.LegendItem((100,60), offset=(70,30)) # args are (size, offset)
|
||||
#l.setParentItem(plt.graphicsItem()) # Note we do NOT call plt.addItem in this case
|
||||
|
||||
c1 = plt.plot([1,3,2,4], pen='r')
|
||||
c2 = plt.plot([2,1,4,3], pen='g')
|
||||
l.addItem(c1, 'red plot')
|
||||
l.addItem(c2, 'green plot')
|
||||
c1 = plt.plot([1,3,2,4], pen='r', name='red plot')
|
||||
c2 = plt.plot([2,1,4,3], pen='g', fillLevel=0, fillBrush=(255,255,255,30), name='green plot')
|
||||
#l.addItem(c1, 'red plot')
|
||||
#l.addItem(c2, 'green plot')
|
||||
|
||||
|
||||
## Start Qt event loop unless running in interactive mode or using pyside.
|
||||
|
63
graphicsItems/GraphicsWidgetAnchor.py
Normal file
63
graphicsItems/GraphicsWidgetAnchor.py
Normal file
@ -0,0 +1,63 @@
|
||||
from ..Qt import QtGui, QtCore
|
||||
from ..Point import Point
|
||||
|
||||
|
||||
class GraphicsWidgetAnchor:
|
||||
"""
|
||||
Class used to allow GraphicsWidgets to anchor to a specific position on their
|
||||
parent.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.__parent = None
|
||||
self.__parentAnchor = None
|
||||
self.__itemAnchor = None
|
||||
self.__offset = (0,0)
|
||||
if hasattr(self, 'geometryChanged'):
|
||||
self.geometryChanged.connect(self.__geometryChanged)
|
||||
|
||||
def anchor(self, itemPos, parentPos, offset=(0,0)):
|
||||
"""
|
||||
Anchors the item at its local itemPos to the item's parent at parentPos.
|
||||
Both positions are expressed in values relative to the size of the item or parent;
|
||||
a value of 0 indicates left or top edge, while 1 indicates right or bottom edge.
|
||||
|
||||
Optionally, offset may be specified to introduce an absolute offset.
|
||||
|
||||
Example: anchor a box such that its upper-right corner is fixed 10px left
|
||||
and 10px down from its parent's upper-right corner::
|
||||
|
||||
box.anchor(itemPos=(1,0), parentPos=(1,0), offset=(-10,10))
|
||||
"""
|
||||
parent = self.parentItem()
|
||||
if parent is None:
|
||||
raise Exception("Cannot anchor; parent is not set.")
|
||||
|
||||
if self.__parent is not parent:
|
||||
if self.__parent is not None:
|
||||
self.__parent.geometryChanged.disconnect(self.__geometryChanged)
|
||||
|
||||
self.__parent = parent
|
||||
parent.geometryChanged.connect(self.__geometryChanged)
|
||||
|
||||
self.__itemAnchor = itemPos
|
||||
self.__parentAnchor = parentPos
|
||||
self.__offset = offset
|
||||
self.__geometryChanged()
|
||||
|
||||
def __geometryChanged(self):
|
||||
if self.__parent is None:
|
||||
return
|
||||
if self.__itemAnchor is None:
|
||||
return
|
||||
|
||||
o = self.mapToParent(Point(0,0))
|
||||
a = self.boundingRect().bottomRight() * Point(self.__itemAnchor)
|
||||
a = self.mapToParent(a)
|
||||
p = self.__parent.boundingRect().bottomRight() * Point(self.__parentAnchor)
|
||||
off = Point(self.__offset)
|
||||
pos = p + (o-a) + off
|
||||
self.setPos(pos)
|
||||
|
||||
|
@ -2,12 +2,14 @@ from .GraphicsWidget import GraphicsWidget
|
||||
from .LabelItem import LabelItem
|
||||
from ..Qt import QtGui, QtCore
|
||||
from .. import functions as fn
|
||||
|
||||
from ..Point import Point
|
||||
from .GraphicsWidgetAnchor import GraphicsWidgetAnchor
|
||||
__all__ = ['LegendItem']
|
||||
|
||||
class LegendItem(GraphicsWidget):
|
||||
class LegendItem(GraphicsWidget, GraphicsWidgetAnchor):
|
||||
"""
|
||||
Displays a legend used for describing the contents of a plot.
|
||||
LegendItems are most commonly created by calling PlotItem.addLegend().
|
||||
|
||||
Note that this item should not be added directly to a PlotItem. Instead,
|
||||
Make it a direct descendant of the PlotItem::
|
||||
@ -15,17 +17,45 @@ class LegendItem(GraphicsWidget):
|
||||
legend.setParentItem(plotItem)
|
||||
|
||||
"""
|
||||
def __init__(self, size, offset):
|
||||
def __init__(self, size=None, offset=None):
|
||||
"""
|
||||
========== ===============================================================
|
||||
Arguments
|
||||
size Specifies the fixed size (width, height) of the legend. If
|
||||
this argument is omitted, the legend will autimatically resize
|
||||
to fit its contents.
|
||||
offset Specifies the offset position relative to the legend's parent.
|
||||
Positive values offset from the left or top; negative values
|
||||
offset from the right or bottom. If offset is None, the
|
||||
legend must be anchored manually by calling anchor() or
|
||||
positioned by calling setPos().
|
||||
========== ===============================================================
|
||||
|
||||
"""
|
||||
|
||||
|
||||
GraphicsWidget.__init__(self)
|
||||
GraphicsWidgetAnchor.__init__(self)
|
||||
self.setFlag(self.ItemIgnoresTransformations)
|
||||
self.layout = QtGui.QGraphicsGridLayout()
|
||||
self.setLayout(self.layout)
|
||||
self.items = []
|
||||
self.size = size
|
||||
self.offset = offset
|
||||
self.setGeometry(QtCore.QRectF(self.offset[0], self.offset[1], self.size[0], self.size[1]))
|
||||
if size is not None:
|
||||
self.setGeometry(QtCore.QRectF(0, 0, self.size[0], self.size[1]))
|
||||
|
||||
def addItem(self, item, title):
|
||||
def setParentItem(self, p):
|
||||
ret = GraphicsWidget.setParentItem(self, p)
|
||||
if self.offset is not None:
|
||||
offset = Point(self.offset)
|
||||
anchorx = 1 if offset[0] <= 0 else 0
|
||||
anchory = 1 if offset[1] <= 0 else 0
|
||||
anchor = (anchorx, anchory)
|
||||
self.anchor(itemPos=anchor, parentPos=anchor, offset=offset)
|
||||
return ret
|
||||
|
||||
def addItem(self, item, name):
|
||||
"""
|
||||
Add a new entry to the legend.
|
||||
|
||||
@ -36,15 +66,30 @@ class LegendItem(GraphicsWidget):
|
||||
title The title to display for this item. Simple HTML allowed.
|
||||
=========== ========================================================
|
||||
"""
|
||||
label = LabelItem(title)
|
||||
label = LabelItem(name)
|
||||
sample = ItemSample(item)
|
||||
row = len(self.items)
|
||||
self.items.append((sample, label))
|
||||
self.layout.addItem(sample, row, 0)
|
||||
self.layout.addItem(label, row, 1)
|
||||
self.updateSize()
|
||||
|
||||
def updateSize(self):
|
||||
if self.size is not None:
|
||||
return
|
||||
|
||||
height = 0
|
||||
width = 0
|
||||
print "-------"
|
||||
for sample, label in self.items:
|
||||
height += max(sample.height(), label.height()) + 3
|
||||
width = max(width, sample.width()+label.width())
|
||||
print width, height
|
||||
print width, height
|
||||
self.setGeometry(0, 0, width+25, height)
|
||||
|
||||
def boundingRect(self):
|
||||
return QtCore.QRectF(0, 0, self.size[0], self.size[1])
|
||||
return QtCore.QRectF(0, 0, self.width(), self.height())
|
||||
|
||||
def paint(self, p, *args):
|
||||
p.setPen(fn.mkPen(255,255,255,100))
|
||||
@ -61,8 +106,16 @@ class ItemSample(GraphicsWidget):
|
||||
return QtCore.QRectF(0, 0, 20, 20)
|
||||
|
||||
def paint(self, p, *args):
|
||||
p.setPen(fn.mkPen(self.item.opts['pen']))
|
||||
opts = self.item.opts
|
||||
|
||||
if opts.get('fillLevel',None) is not None and opts.get('fillBrush',None) is not None:
|
||||
p.setBrush(fn.mkBrush(opts['fillBrush']))
|
||||
p.setPen(fn.mkPen(None))
|
||||
p.drawPolygon(QtGui.QPolygonF([QtCore.QPointF(2,18), QtCore.QPointF(18,2), QtCore.QPointF(18,18)]))
|
||||
|
||||
p.setPen(fn.mkPen(opts['pen']))
|
||||
p.drawLine(2, 18, 18, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -65,6 +65,7 @@ class PlotCurveItem(GraphicsObject):
|
||||
'fillLevel': None,
|
||||
'brush': None,
|
||||
'stepMode': False,
|
||||
'name': None
|
||||
}
|
||||
self.setClickable(kargs.get('clickable', False))
|
||||
self.setData(*args, **kargs)
|
||||
@ -238,6 +239,9 @@ class PlotCurveItem(GraphicsObject):
|
||||
self.fillPath = None
|
||||
#self.xDisp = self.yDisp = None
|
||||
|
||||
if 'name' in kargs:
|
||||
self.opts['name'] = kargs['name']
|
||||
|
||||
if 'pen' in kargs:
|
||||
self.setPen(kargs['pen'])
|
||||
if 'shadowPen' in kargs:
|
||||
|
@ -317,6 +317,8 @@ class PlotDataItem(GraphicsObject):
|
||||
## pull in all style arguments.
|
||||
## Use self.opts to fill in anything not present in kargs.
|
||||
|
||||
if 'name' in kargs:
|
||||
self.opts['name'] = kargs['name']
|
||||
|
||||
## if symbol pen/brush are given with no symbol, then assume symbol is 'o'
|
||||
|
||||
|
@ -33,6 +33,7 @@ from .. PlotDataItem import PlotDataItem
|
||||
from .. ViewBox import ViewBox
|
||||
from .. AxisItem import AxisItem
|
||||
from .. LabelItem import LabelItem
|
||||
from .. LegendItem import LegendItem
|
||||
from .. GraphicsWidget import GraphicsWidget
|
||||
from .. ButtonItem import ButtonItem
|
||||
from pyqtgraph.WidgetGroup import WidgetGroup
|
||||
@ -528,6 +529,9 @@ class PlotItem(GraphicsWidget):
|
||||
#c.connect(c, QtCore.SIGNAL('plotChanged'), self.plotChanged)
|
||||
#item.sigPlotChanged.connect(self.plotChanged)
|
||||
#self.plotChanged()
|
||||
name = kargs.get('name', getattr(item, 'opts', {}).get('name', None))
|
||||
if name is not None and self.legend is not None:
|
||||
self.legend.addItem(item, name=name)
|
||||
|
||||
|
||||
def addDataItem(self, item, *args):
|
||||
@ -596,6 +600,16 @@ class PlotItem(GraphicsWidget):
|
||||
|
||||
return item
|
||||
|
||||
def addLegend(self, size=None, offset=(30, 30)):
|
||||
"""
|
||||
Create a new LegendItem and anchor it over the internal ViewBox.
|
||||
Plots will be automatically displayed in the legend if they
|
||||
are created with the 'name' argument.
|
||||
"""
|
||||
self.legend = LegendItem(size, offset)
|
||||
self.legend.setParentItem(self.vb)
|
||||
return self.legend
|
||||
|
||||
def scatterPlot(self, *args, **kargs):
|
||||
if 'pen' in kargs:
|
||||
kargs['symbolPen'] = kargs['pen']
|
||||
|
Loading…
Reference in New Issue
Block a user