Repository: pyqtgraph/pyqtgraph

Issue:
GradientLegend
### Short description
GradientLegend generates the legend upside down

### Code to reproduce

```python
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QWidget, QApplication
import pyqtgraph as pg
import sys

class AnalysePlot(QWidget):

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.setWindowTitle('Model parameter endring')
        self.setAutoFillBackground(True)
        self.setStyleSheet("color: yellow;"
                           "background-color: rgba(0, 0, 0, 255);")

        self.view = pg.GraphicsView(self)
        self.layout = pg.GraphicsLayout(border=(100, 100, 100))
        self.view.setCentralItem(self.layout)
        self.view.show()
        self.view.resize(640, 480)
        self.layout.setSpacing(5)

        self.p1 = self.layout.addPlot(title="Parametrene")
        self.p1.setFixedWidth(620)
        self.p1.setFixedHeight(460)
        self.p1.showGrid(1, 1, 0.3)

        self.gradLeg = pg.GradientLegend(size=(25, 100), offset=(-15, 15))

        self.updateGraph()

    def updateGraph(self):
        self.p1.clear()

        startParams = [-721, 617, 0, -666, 0, 446, 2586, 0, 4, 0, 0, -210, 2722, 165, 12, 0, 588, 0, 140, -689]
        params = [-719, 616, -11, -672, -17, 447, 2605, 2, 8, -1, 0.0, -209, 2722.0, 165.0, 12.0, 0.0, 588.0, 0.0,\
                          140.0, -689.0]
        arrayDif = []

        grad = QtGui.QLinearGradient(QtCore.QPointF(0, -20), QtCore.QPointF(20, 20))
        grad.setColorAt(0.0, pg.mkColor('r'))
        grad.setColorAt(0.125, pg.mkColor('#FF9933'))
        grad.setColorAt(0.25, pg.mkColor('y'))
        grad.setColorAt(0.375, pg.mkColor('g'))
        grad.setColorAt(0.5, pg.mkColor('b'))
        grad.setColorAt(0.625, pg.mkColor('g'))
        grad.setColorAt(0.75, pg.mkColor('y'))
        grad.setColorAt(0.875, pg.mkColor('#FF9933'))
        grad.setColorAt(1.0, pg.mkColor('r'))
        self.brush = QtGui.QBrush(grad)

        self.gradLeg.setGradient(grad)
        legendDict = {
            "-5": 0.375,
            "-10": 0.25,
            "-15": 0.125,
            "-20": 0,
            "0": 0.5,
            "5": 0.625,
            "10": 0.75,
            "15": 0.875,
            "20": 1
        }
        self.gradLeg.setLabels(legendDict)

        self.p1.setTitle('Parametrene')
        self.p1.setLabel('left', 'Endring [mm]')
        self.p1.setLabel('bottom', 'Parameter')
        self.p1.setLabel('right', 'Endring [mm]')

        for i in range(len(startParams)):
            arrayDif.append(startParams[i] - params[i])

        bargraph = pg.BarGraphItem(x=range(20), height=arrayDif, width=0.6, brush=self.brush)
        self.p1.addItem(bargraph)
        self.p1.addItem(self.gradLeg)

        ax = self.p1.getAxis('bottom')
        ticks = [(0, 'p2'), (1, 'p3'), (2, 'p4'), (3, 'p8'), (4, 'p9'), (5, 'p10'), (6, 'p12'),\
                 (7, 'p13'),  (8, 'p14'), (9, 'p16'), (10, 'p17'), (11, 'p18'), (12, 'p21'),\
                 (13, 'p23'), (14, 'p24'), (15, 'p25'), (16, 'p27'), (17, 'p28'), (18, 'p29'), \
                 (19, 'p40')]
        ax.setTicks([ticks])

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ui = AnalysePlot()
    ui.show()
    app.exec_()
```


### Expected behavior
<!-- What should happen? -->
Legend should be right side up

### Real behavior
Legend is generated upside down

### Tested environment(s)

 * PyQtGraph version: 0.11.1
 * Qt Python binding: PyQt5 5.15.2 Qt 5.15.2
 * Python version:  3.7
 * Operating system:  Windows 10 Pro 64bit
 * Installation method: in PyCharm




Discussion:
Hi @Breviel I hope you don't mind, I edited your code a bit to make it easier to read.

Resolving patch:
diff --git a/pyqtgraph/graphicsItems/GradientLegend.py b/pyqtgraph/graphicsItems/GradientLegend.py
--- a/pyqtgraph/graphicsItems/GradientLegend.py
+++ b/pyqtgraph/graphicsItems/GradientLegend.py
@@ -6,7 +6,7 @@
 
 class GradientLegend(UIGraphicsItem):
     """
-    Draws a color gradient rectangle along with text labels denoting the value at specific 
+    Draws a color gradient rectangle along with text labels denoting the value at specific
     points along the gradient.
     """
     
@@ -50,6 +50,9 @@ def paint(self, p, opt, widget):
         if unit[0] is None:  
             return
         
+        ## Have to scale painter so that text and gradients are correct size and not upside down
+        p.scale(unit[0], -unit[1])
+
         ## determine max width of all labels
         labelWidth = 0
         labelHeight = 0
@@ -58,57 +61,54 @@ def paint(self, p, opt, widget):
             labelWidth = max(labelWidth, b.width())
             labelHeight = max(labelHeight, b.height())
             
-        labelWidth *= unit[0]
-        labelHeight *= unit[1]
-        
         textPadding = 2  # in px
         
+        xR = rect.right()  / unit[0]
+        xL = rect.left()   / unit[0]
+        yB = -(rect.top()    / unit[1])
+        yT = -(rect.bottom() / unit[1])
+        
+        # coordinates describe edges of text and bar, additional margins will be added for background
         if self.offset[0] < 0:
-            x3 = rect.right() + unit[0] * self.offset[0]
-            x2 = x3 - labelWidth - unit[0]*textPadding*2
-            x1 = x2 - unit[0] * self.size[0]
+            x3 = xR + self.offset[0] # right edge from right edge of view, offset is negative!
+            x2 = x3 - labelWidth - 2*textPadding # right side of color bar
+            x1 = x2 - self.size[0]               # left side of color bar
         else:
-            x1 = rect.left() + unit[0] * self.offset[0]
-            x2 = x1 + unit[0] * self.size[0]
-            x3 = x2 + labelWidth + unit[0]*textPadding*2
+            x1 = xL + self.offset[0] # left edge from left edge of view
+            x2 = x1 + self.size[0]
+            x3 = x2 + labelWidth + 2*textPadding # leave room for 2x textpadding between bar and text
         if self.offset[1] < 0:
-            y2 = rect.top() - unit[1] * self.offset[1]
-            y1 = y2 + unit[1] * self.size[1]
+            y2 = yB + self.offset[1] # bottom edge from bottom of view, offset is negative!
+            y1 = y2 - self.size[1]
         else:
-            y1 = rect.bottom() - unit[1] * self.offset[1]
-            y2 = y1 - unit[1] * self.size[1]
+            y1 = yT + self.offset[1] # top edge from top of view
+            y2 = y1 + self.size[1]
         self.b = [x1,x2,x3,y1,y2,labelWidth]
-            
+
         ## Draw background
         p.setPen(self.pen)
         p.setBrush(QtGui.QBrush(QtGui.QColor(255,255,255,100)))
         rect = QtCore.QRectF(
-            QtCore.QPointF(x1 - unit[0]*textPadding, y1 + labelHeight/2 + unit[1]*textPadding), 
-            QtCore.QPointF(x3, y2 - labelHeight/2 - unit[1]*textPadding)
+            QtCore.QPointF(x1 - textPadding, y1-labelHeight/2 - textPadding), # extra left/top padding 
+            QtCore.QPointF(x3 + textPadding, y2+labelHeight/2 + textPadding)  # extra bottom/right padding
         )
         p.drawRect(rect)
-        
-        
-        ## Have to scale painter so that text and gradients are correct size. Bleh.
-        p.scale(unit[0], unit[1])
-        
+
         ## Draw color bar
-        self.gradient.setStart(0, y1/unit[1])
-        self.gradient.setFinalStop(0, y2/unit[1])
+        self.gradient.setStart(0, y1)
+        self.gradient.setFinalStop(0, y2)
         p.setBrush(self.gradient)
         rect = QtCore.QRectF(
-            QtCore.QPointF(x1/unit[0], y1/unit[1]), 
-            QtCore.QPointF(x2/unit[0], y2/unit[1])
+            QtCore.QPointF(x1, y1), 
+            QtCore.QPointF(x2, y2)
         )
         p.drawRect(rect)
-        
-        
+
         ## draw labels
         p.setPen(QtGui.QPen(QtGui.QColor(0,0,0)))
-        tx = x2 + unit[0]*textPadding
-        lh = labelHeight/unit[1]
+        tx = x2 + 2 * textPadding # margin between bar and text
+        lh = labelHeight
+        lw = labelWidth
         for k in self.labels:
             y = y1 + self.labels[k] * (y2-y1)
-            p.drawText(QtCore.QRectF(tx/unit[0], y/unit[1] - lh/2.0, 1000, lh), QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, str(k))
-        
-        
+            p.drawText(QtCore.QRectF(tx, y - lh/2, lw, lh), QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, str(k))


Test patch: