Source code for pyqtgraph.graphicsItems.GraphicsLayout

from .. import functions as fn
from ..Qt import QtWidgets
from .GraphicsWidget import GraphicsWidget
from .LabelItem import LabelItem
from .PlotItem import PlotItem

## Must be imported at the end to avoid cyclic-dependency hell:
from .ViewBox import ViewBox

__all__ = ['GraphicsLayout']
[docs] class GraphicsLayout(GraphicsWidget): """ Used for laying out GraphicsWidgets in a grid. This is usually created automatically as part of a :class:`GraphicsLayoutWidget <pyqtgraph.GraphicsLayoutWidget>`. """
[docs] def __init__(self, parent=None, border=None): GraphicsWidget.__init__(self, parent) if border is True: border = (100,100,100) elif border is False: border = None self.border = border self.layout = QtWidgets.QGraphicsGridLayout() self.setLayout(self.layout) self.items = {} ## item: [(row, col), (row, col), ...] lists all cells occupied by the item self.rows = {} ## row: {col1: item1, col2: item2, ...} maps cell location to item self.itemBorders = {} ## {item1: QtWidgets.QGraphicsRectItem, ...} border rects self.currentRow = 0 self.currentCol = 0 self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding))
#def resizeEvent(self, ev): #ret = GraphicsWidget.resizeEvent(self, ev) #print self.pos(), self.mapToDevice(self.rect().topLeft()) #return ret
[docs] def setBorder(self, *args, **kwds): """ Set the pen used to draw border between cells. See :func:`mkPen <pyqtgraph.mkPen>` for arguments. """ self.border = fn.mkPen(*args, **kwds) for borderRect in self.itemBorders.values(): borderRect.setPen(self.border)
[docs] def nextRow(self): """Advance to next row for automatic item placement""" self.currentRow += 1 self.currentCol = -1 self.nextColumn()
[docs] def nextColumn(self): """Advance to next available column (generally only for internal use--called by addItem)""" self.currentCol += 1 while self.getItem(self.currentRow, self.currentCol) is not None: self.currentCol += 1
[docs] def nextCol(self, *args, **kargs): """Alias of nextColumn""" return self.nextColumn(*args, **kargs)
[docs] def addPlot(self, row=None, col=None, rowspan=1, colspan=1, **kargs): """ Create a PlotItem and place it in the next available cell (or in the cell specified) All extra keyword arguments are passed to :func:`PlotItem.__init__ <pyqtgraph.PlotItem.__init__>` Returns the created item. """ plot = PlotItem(**kargs) self.addItem(plot, row, col, rowspan, colspan) return plot
[docs] def addViewBox(self, row=None, col=None, rowspan=1, colspan=1, **kargs): """ Create a ViewBox and place it in the next available cell (or in the cell specified) All extra keyword arguments are passed to :func:`ViewBox.__init__ <pyqtgraph.ViewBox.__init__>` Returns the created item. """ vb = ViewBox(**kargs) self.addItem(vb, row, col, rowspan, colspan) return vb
[docs] def addLabel(self, text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs): """ Create a LabelItem with *text* and place it in the next available cell (or in the cell specified) All extra keyword arguments are passed to :func:`LabelItem.__init__ <pyqtgraph.LabelItem.__init__>` Returns the created item. To create a vertical label, use *angle* = -90. """ text = LabelItem(text, **kargs) self.addItem(text, row, col, rowspan, colspan) return text
[docs] def addLayout(self, row=None, col=None, rowspan=1, colspan=1, **kargs): """ Create an empty GraphicsLayout and place it in the next available cell (or in the cell specified) All extra keyword arguments are passed to :func:`GraphicsLayout.__init__ <pyqtgraph.GraphicsLayout.__init__>` Returns the created item. """ layout = GraphicsLayout(**kargs) self.addItem(layout, row, col, rowspan, colspan) return layout
[docs] def addItem(self, item, row=None, col=None, rowspan=1, colspan=1): """ Add an item to the layout and place it in the next available cell (or in the cell specified). The item must be an instance of a QGraphicsWidget subclass. """ if row is None: row = self.currentRow if col is None: col = self.currentCol self.items[item] = [] for i in range(rowspan): for j in range(colspan): row2 = row + i col2 = col + j if row2 not in self.rows: self.rows[row2] = {} self.rows[row2][col2] = item self.items[item].append((row2, col2)) borderRect = QtWidgets.QGraphicsRectItem() borderRect.setParentItem(self) borderRect.setZValue(1e3) borderRect.setPen(fn.mkPen(self.border)) self.itemBorders[item] = borderRect item.geometryChanged.connect(self._updateItemBorder) self.layout.addItem(item, row, col, rowspan, colspan) self.layout.activate() # Update layout, recalculating bounds. # Allows some PyQtGraph features to also work without Qt event loop. self.nextColumn()
[docs] def getItem(self, row, col): """Return the item in (*row*, *col*). If the cell is empty, return None.""" return self.rows.get(row, {}).get(col, None)
def boundingRect(self): return self.rect()
[docs] def itemIndex(self, item): """Return the numerical index of GraphicsItem object passed in Parameters ---------- item : QGraphicsLayoutItem Item to query the index position of Returns ------- int Index of the item within the graphics layout Raises ------ ValueError Raised if item could not be found inside the GraphicsLayout instance. """ for i in range(self.layout.count()): if self.layout.itemAt(i).graphicsItem() is item: return i raise ValueError(f"Could not determine index of item {item}")
[docs] def removeItem(self, item): """Remove *item* from the layout.""" ind = self.itemIndex(item) self.layout.removeAt(ind) self.scene().removeItem(item) for r, c in self.items[item]: del self.rows[r][c] del self.items[item] item.geometryChanged.disconnect(self._updateItemBorder) itemBorder = self.itemBorders.pop(item) self.scene().removeItem(itemBorder) self.update()
[docs] def clear(self): """Remove all items from the layout and set the current row and column to 0 """ for i in list(self.items.keys()): self.removeItem(i) self.currentRow = 0 self.currentCol = 0
def setContentsMargins(self, *args): # Wrap calls to layout. This should happen automatically, but there # seems to be a Qt bug: # http://stackoverflow.com/questions/27092164/margins-in-pyqtgraphs-graphicslayout self.layout.setContentsMargins(*args) def setSpacing(self, *args): self.layout.setSpacing(*args) def _updateItemBorder(self): if self.border is None: return item = self.sender() if item is None: return r = item.mapRectToParent(item.boundingRect()) self.itemBorders[item].setRect(r)