Repository: pyqtgraph/pyqtgraph

Issue:
Need a few spaces between LegendItem symbols and their names
When I add a legend to a plot, the legend marks (for example, scatter plot marks) are too close to the names i wrote to them. Cannot you fix it?

https://imgur.com/a/uqJPg — here is it.

P.S. Your library is really cool, it's much better than slow matplotlib = )


Discussion:
i had the same problem and i think i found the bug. it is a bug in **legenditem.py line 112 & 113**.
that is in **method updateSize()**.
The same bug also moves the text further away from the symbol each time a legend row is appended!

my Fix:
instead of **sample.height()** and **sample.width()** it should be:
**sample.boundingRect().height()** & **sample.boundingRect().width()**

```
    def updateSize(self):
        if self.size is not None:
            return
            
        height = 0
        width = 0
        #print("-------")
        for sample, label in self.items:
            height += max(sample.boundingRect().height(), label.height()) + 3
            width = max(width, sample.boundingRect().width()+label.width())
            #print(width, height)
        #print width, height
        self.setGeometry(0, 0, width+25, height)
```

i think it was intented to use the boundingRect but it was forgotten to use it here!
when i make these changes it works flawlessy!! 



Thanks for the tip gdotmueller! 
Additionaly, the legend text should be 'left' aligned instead of the default 'center'.
````
def addItem(self, item, name):
        #label = LabelItem(name)
        label = LabelItem(name, justify='left')
        if isinstance(item, ItemSample):
            sample = item
        else:
            sample = ItemSample(item)        
        row = self.layout.rowCount()
        self.items.append((sample, label))
        self.layout.addItem(sample, row, 0)
        self.layout.addItem(label, row, 1)
        self.updateSize()`

Best Regards
Falk
I fixed the overlapping issue this way; in **legendItem.py** file of the library: 

```
    def addItem(self, item, name):
        label = LabelItem(name, justify='left')
        if isinstance(item, ItemSample):
            sample = item
        else:
            sample = ItemSample(item)        
        row = self.layout.rowCount()
        self.items.append((sample, label))
        self.layout.setRowAlignment(row, QtCore.Qt.AlignLeft) #added
        self.layout.addItem(sample, row, 0)
        self.layout.addItem(LabelItem(''), row, 1) #spacer
        self.layout.addItem(label, row, 2)
        self.updateSize()
```
added an empty column first, and justified left thanks for @FalkMusick . 



Resolving patch:
diff --git a/pyqtgraph/graphicsItems/LegendItem.py b/pyqtgraph/graphicsItems/LegendItem.py
--- a/pyqtgraph/graphicsItems/LegendItem.py
+++ b/pyqtgraph/graphicsItems/LegendItem.py
@@ -8,6 +8,7 @@
 from .GraphicsWidgetAnchor import GraphicsWidgetAnchor
 __all__ = ['LegendItem']
 
+
 class LegendItem(GraphicsWidget, GraphicsWidgetAnchor):
     """
     Displays a legend used for describing the contents of a plot.
@@ -19,47 +20,120 @@ class LegendItem(GraphicsWidget, GraphicsWidgetAnchor):
         legend.setParentItem(plotItem)
 
     """
-    def __init__(self, size=None, offset=None):
+    def __init__(self, size=None, offset=None, horSpacing=25, verSpacing=0, pen=None,
+                 brush=None, labelTextColor=None, **kwargs):
         """
         ==============  ===============================================================
         **Arguments:**
         size            Specifies the fixed size (width, height) of the legend. If
-                        this argument is omitted, the legend will autimatically resize
+                        this argument is omitted, the legend will automatically 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().
+        horSpacing      Specifies the spacing between the line symbol and the label.
+        verSpacing      Specifies the spacing between individual entries of the legend
+                        vertically. (Can also be negative to have them really close)
+        pen             Pen to use when drawing legend border. Any single argument
+                        accepted by :func:`mkPen <pyqtgraph.mkPen>` is allowed.
+        brush           QBrush to use as legend background filling. Any single argument
+                        accepted by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed.
+        labelTextColor  Pen to use when drawing legend text. Any single argument
+                        accepted by :func:`mkPen <pyqtgraph.mkPen>` is allowed.
         ==============  ===============================================================
-        
+
         """
-        
-        
+
+
         GraphicsWidget.__init__(self)
         GraphicsWidgetAnchor.__init__(self)
         self.setFlag(self.ItemIgnoresTransformations)
         self.layout = QtGui.QGraphicsGridLayout()
+        self.layout.setVerticalSpacing(verSpacing)
+        self.layout.setHorizontalSpacing(horSpacing)
+
         self.setLayout(self.layout)
         self.items = []
         self.size = size
-        self.offset = offset
         if size is not None:
             self.setGeometry(QtCore.QRectF(0, 0, self.size[0], self.size[1]))
-        
+
+        self.opts = {
+            'pen': fn.mkPen(pen),
+            'brush': fn.mkBrush(brush),
+            'labelTextColor': labelTextColor,
+            'offset': offset,
+        }
+
+        self.opts.update(kwargs)
+
+    def offset(self):
+        return self.opts['offset']
+
+    def setOffset(self, offset):
+        self.opts['offset'] = offset
+
+        offset = Point(self.opts['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)
+
+    def pen(self):
+        return self.opts['pen']
+
+    def setPen(self, *args, **kargs):
+        """
+        Sets the pen used to draw lines between points.
+        *pen* can be a QPen or any argument accepted by
+        :func:`pyqtgraph.mkPen() <pyqtgraph.mkPen>`
+        """
+        pen = fn.mkPen(*args, **kargs)
+        self.opts['pen'] = pen
+
+        self.paint()
+
+    def brush(self):
+        return self.opts['brush']
+
+    def setBrush(self, *args, **kargs):
+        brush = fn.mkBrush(*args, **kargs)
+        if self.opts['brush'] == brush:
+            return
+        self.opts['brush'] = brush
+
+        self.paint()
+
+    def labelTextColor(self):
+        return self.opts['labelTextColor']
+
+    def setLabelTextColor(self, *args, **kargs):
+        """
+        Sets the color of the label text.
+        *pen* can be a QPen or any argument accepted by
+        :func:`pyqtgraph.mkColor() <pyqtgraph.mkPen>`
+        """
+        self.opts['labelTextColor'] = fn.mkColor(*args, **kargs)
+        for sample, label in self.items:
+            label.setAttr('color', self.opts['labelTextColor'])
+
+        self.paint()
+
     def setParentItem(self, p):
         ret = GraphicsWidget.setParentItem(self, p)
         if self.offset is not None:
-            offset = Point(self.offset)
+            offset = Point(self.opts['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. 
+        Add a new entry to the legend.
 
         ==============  ========================================================
         **Arguments:**
@@ -70,63 +144,63 @@ def addItem(self, item, name):
         title           The title to display for this item. Simple HTML allowed.
         ==============  ========================================================
         """
-        label = LabelItem(name)
+        label = LabelItem(name, color=self.opts['labelTextColor'], justify='left')
         if isinstance(item, ItemSample):
             sample = item
         else:
-            sample = ItemSample(item)        
+            sample = ItemSample(item)
+
         row = self.layout.rowCount()
         self.items.append((sample, label))
         self.layout.addItem(sample, row, 0)
         self.layout.addItem(label, row, 1)
         self.updateSize()
-    
+
     def removeItem(self, item):
         """
-        Removes one item from the legend. 
+        Removes one item from the legend.
 
         ==============  ========================================================
         **Arguments:**
         item            The item to remove or its name.
         ==============  ========================================================
         """
-        # Thanks, Ulrich!
-        # cycle for a match
         for sample, label in self.items:
             if sample.item is item or label.text == item:
-                self.items.remove( (sample, label) )    # remove from itemlist
+                self.items.remove((sample, label))      # remove from itemlist
                 self.layout.removeItem(sample)          # remove from layout
                 sample.close()                          # remove from drawing
                 self.layout.removeItem(label)
                 label.close()
                 self.updateSize()                       # redraq box
+                return                                  # return after first match
+
+    def clear(self):
+        """Removes all items from legend."""
+        for sample, label in self.items:
+            self.layout.removeItem(sample)
+            self.layout.removeItem(label)
+
+        self.items = []
+        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.sizeHint(QtCore.Qt.MinimumSize, sample.size()).width() +
-                                label.sizeHint(QtCore.Qt.MinimumSize, label.size()).width()))
-            #print(width, height)
-        #print width, height
-        self.setGeometry(0, 0, width+25, height)
-    
+
+        self.setGeometry(0, 0, 0, 0)
+
     def boundingRect(self):
         return QtCore.QRectF(0, 0, self.width(), self.height())
-    
+
     def paint(self, p, *args):
-        p.setPen(fn.mkPen(255,255,255,100))
-        p.setBrush(fn.mkBrush(100,100,100,50))
+        p.setPen(self.opts['pen'])
+        p.setBrush(self.opts['brush'])
         p.drawRect(self.boundingRect())
 
     def hoverEvent(self, ev):
         ev.acceptDrags(QtCore.Qt.LeftButton)
-        
+
     def mouseDragEvent(self, ev):
         if ev.button() == QtCore.Qt.LeftButton:
             dpos = ev.pos() - ev.lastPos()
@@ -135,42 +209,39 @@ def mouseDragEvent(self, ev):
 
 class ItemSample(GraphicsWidget):
     """ Class responsible for drawing a single item in a LegendItem (sans label).
-    
+
     This may be subclassed to draw custom graphics in a Legend.
     """
     ## Todo: make this more generic; let each item decide how it should be represented.
     def __init__(self, item):
         GraphicsWidget.__init__(self)
         self.item = item
-    
+
     def boundingRect(self):
         return QtCore.QRectF(0, 0, 20, 20)
-        
+
     def paint(self, p, *args):
-        #p.setRenderHint(p.Antialiasing)  # only if the data is antialiased.
         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)]))
-        
+
+        if opts['antialias']:
+            p.setRenderHint(p.Antialiasing)
+
         if not isinstance(self.item, ScatterPlotItem):
             p.setPen(fn.mkPen(opts['pen']))
-            p.drawLine(2, 18, 18, 2)
-        
+            p.drawLine(0, 11, 20, 11)
+
         symbol = opts.get('symbol', None)
         if symbol is not None:
             if isinstance(self.item, PlotDataItem):
                 opts = self.item.scatter.opts
-                
+
             pen = fn.mkPen(opts['pen'])
             brush = fn.mkBrush(opts['brush'])
             size = opts['size']
-            
-            p.translate(10,10)
+
+            p.translate(10, 10)
             path = drawSymbol(p, symbol, size, pen, brush)
-        
-        
-        
-        
+
+
+
+


Test patch: