def drawRoundedFrame(self, painter, rect, xRadius, yRadius, palette, lineWidth, frameStyle): """ Draw a rectangular frame with rounded borders :param QPainter painter: Painter :param QRectF rect: Frame rectangle :param float xRadius: x-radius of the ellipses defining the corners :param float yRadius: y-radius of the ellipses defining the corners :param QPalette palette: `QPalette.WindowText` is used for plain borders, `QPalette.Dark` and `QPalette.Light` for raised or sunken borders :param int lineWidth: Line width :param int frameStyle: bitwise ORĀ“ed value of `QFrame.Shape` and `QFrame.Shadow` """ painter.save() painter.setRenderHint(QPainter.Antialiasing, True) painter.setBrush(Qt.NoBrush) lw2 = lineWidth * 0.5 r = rect.adjusted(lw2, lw2, -lw2, -lw2) path = QPainterPath() path.addRoundedRect(r, xRadius, yRadius) Plain, Sunken, Raised = list(range(3)) style = Plain if (frameStyle & QFrame.Sunken) == QFrame.Sunken: style = Sunken if (frameStyle & QFrame.Raised) == QFrame.Raised: style = Raised if style != Plain and path.elementCount() == 17: pathList = [QPainterPath() for _i in range(8)] for i in range(4): j = i * 4 + 1 pathList[2 * i].moveTo( path.elementAt(j - 1).x, path.elementAt(j - 1).y) pathList[2 * i].cubicTo( path.elementAt(j + 0).x, path.elementAt(j + 0).y, path.elementAt(j + 1).x, path.elementAt(j + 1).y, path.elementAt(j + 2).x, path.elementAt(j + 2).y, ) pathList[2 * i + 1].moveTo( path.elementAt(j + 2).x, path.elementAt(j + 2).y) pathList[2 * i + 1].lineTo( path.elementAt(j + 3).x, path.elementAt(j + 3).y) c1 = QColor(palette.color(QPalette.Dark)) c2 = QColor(palette.color(QPalette.Light)) if style == Raised: c1, c2 = c2, c1 for i in range(5): r = pathList[2 * i].controlPointRect() arcPen = QPen() arcPen.setCapStyle(Qt.FlatCap) arcPen.setWidth(lineWidth) linePen = QPen() linePen.setCapStyle(Qt.FlatCap) linePen.setWidth(lineWidth) if i == 0: arcPen.setColor(c1) linePen.setColor(c1) elif i == 1: gradient = QLinearGradient() gradient.setStart(r.topLeft()) gradient.setFinalStop(r.bottomRight()) gradient.setColorAt(0.0, c1) gradient.setColorAt(1.0, c2) arcPen.setBrush(gradient) linePen.setColor(c2) elif i == 2: arcPen.setColor(c2) linePen.setColor(c2) elif i == 3: gradient = QLinearGradient() gradient.setStart(r.bottomRight()) gradient.setFinalStop(r.topLeft()) gradient.setColorAt(0.0, c2) gradient.setColorAt(1.0, c1) arcPen.setBrush(gradient) linePen.setColor(c1) painter.setPen(arcPen) painter.drawPath(pathList[2 * i]) painter.setPen(linePen) painter.drawPath(pathList[2 * i + 1]) else: pen = QPen(palette.color(QPalette.WindowText), lineWidth) painter.setPen(pen) painter.drawPath(path) painter.restore()
class _GradientLegend(GraphicsWidget): """Class to make GradientLegend a GraphicsWidget. Draws a color gradient rectangle along with text labels denoting the value at specific points along the gradient. Parameters ---------- size : list of int, optional Size of the widget within the GraphicsWidget rectangle. colors : a list of RGB codes, optional The lookup table to be used to design the gradient. labels : dict of keys = strings and values = int The labels that will appear along the colorbar. The values determine the sequence of labels in descending order. minVal : int, optional If labels is None, so only minVal and maxVal are displayed in the beggining and in the end of the colorbar. maxVal : int, optional If labels is None, so only minVal and maxVal are displayed in the beggining and in the end of the colorbar. """ def __init__(self, size=None, colors=None, labels=None, minVal=None, maxVal=None): GraphicsWidget.__init__(self) self.setAcceptedMouseButtons(Qt.NoButton) self.size = size # if min and max values are None, assume normalized data self.minVal = 0 if minVal is None else minVal self.maxVal = 1 if maxVal is None else maxVal self.labels = {1: 'min', 0: 'max'} if labels is None else labels self.label_format = '{: .3f}' self.gradient = QLinearGradient() if colors is None: self.colors = [[0, 0, 0], [255, 0, 0]] else: self.colors = colors self.setIntColorScale(colors=self.colors, minVal=self.minVal, maxVal=self.maxVal, labels=self.labels) def setIntColorScale(self, colors, minVal=None, maxVal=None, labels=None): # generate color gradient g = QLinearGradient() for i in range(len(colors)): x = float(i) / len(colors) g.setColorAt(x, QColor(colors[i][0], colors[i][1], colors[i][2])) self._setGradient(g) # add labels if labels is None and (minVal is None or maxVal is None): self.setLabels(self.labels) elif labels is None: self.setLabels({1: str(minVal), 0: str(maxVal)}) else: self.setLabels(labels) def _setGradient(self, g): self.gradient = g self.update() def setLimits(self, data): minVal = data[0] maxVal = data[1] if minVal == self.minVal and maxVal == self.maxVal: return self.minVal = minVal self.maxVal = maxVal for k in self.labels.keys(): newv = minVal + (1 - k) * (maxVal - minVal) newv = self.label_format.format(newv) self.labels[k] = newv self.setLabels(self.labels) def setLabels(self, l): """ Define labels to appear next to the color scale. Accepts a dict of {text: value} pairs. """ self.labels = l self.update() def paint(self, p, opt, widget): GraphicsWidget.paint(self, p, opt, widget) rect = self.boundingRect() # Boundaries of visible area in scene coord size = self.size if self.size is not None \ else [rect.right()-rect.left(), rect.bottom() - rect.top()] # determine max width of all labels textPadding = 2 # in px labelWidth = 0 labelHeight = 0 for val in self.labels.values(): b = p.boundingRect(QRectF(0, 0, 0, 0), Qt.AlignLeft | Qt.AlignVCenter, str(val)) labelWidth = max(labelWidth, b.width()) labelHeight = max(labelHeight, b.height()) x1_back = (rect.right() - rect.left() - size[0]) / 2 x2_back = (rect.right() - rect.left() + size[0]) / 2 y1_back = (rect.bottom() - rect.top() - size[1]) / 2 y2_back = (rect.bottom() - rect.top() + size[1]) / 2 x1_grad = x1_back + textPadding * 2 x2_grad = x2_back - (labelWidth + textPadding * 2) y1_grad = y1_back + (labelHeight / 2 + textPadding) y2_grad = y2_back - (labelHeight / 2 + textPadding) # Draw background p.setPen(QPen(QColor(0, 0, 0, 0))) p.setBrush(QBrush(QColor(255, 255, 255, 0))) rect = QRectF(QPointF(x1_back, y1_back), QPointF(x2_back, y2_back)) p.drawRect(rect) # Draw color bar self.gradient.setStart(0, y2_grad) self.gradient.setFinalStop(0, y1_grad) p.setPen(QPen(QColor(0, 0, 0))) p.setBrush(self.gradient) rect = QRectF(QPointF(x1_grad, y1_grad), QPointF(x2_grad, y2_grad)) p.drawRect(rect) # draw labels tx = x2_grad + textPadding * 2 lw = labelWidth lh = labelHeight for key, val in self.labels.items(): y = y1_grad + key * (y2_grad - y1_grad) p.drawText(QRectF(tx, y - lh / 2.0, lw, lh), Qt.AlignLeft | Qt.AlignVCenter, str(val)) self.setMinimumWidth(labelWidth + 2 * textPadding + 20)