Repository: pyqtgraph/pyqtgraph

Issue:
SVGExporter: Size of exported SVG image canvas is not set
<!-- In the following, please describe your issue in detail! -->
<!-- If some of the sections do not apply, just remove them. -->

### Short description
The size of an exported SVG image canvas is not set.

### Code to reproduce
<!-- Please provide a minimal working example that reproduces the issue in the code block below.
     Ideally, this should be a full example someone else could run without additional setup. -->
```python
import pyqtgraph as pg
from  pyqtgraph import exporters

app = pg.mkQApp()

pw = pg.plot([1,2],[2,1])

ex = exporters.SVGExporter(pw.plotItem)
ex.export(fileName="test.svg")
```

Screenshots are taken in Inkscape.

### Expected behavior
<!-- What should happen? -->
![image](https://user-images.githubusercontent.com/31772910/78728648-2db22300-7938-11ea-83d6-db13561a48c0.png)


### Real behavior
![image](https://user-images.githubusercontent.com/31772910/78728628-1f640700-7938-11ea-9709-28997a4b7c0d.png)

### Tested environment(s)

 * PyQtGraph version: Latest commit from `develop` ( 88931bc4a57c62445f20a53166306b16c00763bf )
 * Qt Python binding: PyQt5 5.14.1 Qt 5.14.1
 * Python version: 3.8.2
 * NumPy version: 1.18.2
 * Operating system: Linux 5.5.7-1-MANJARO x86_64 19.0.2 Kyria
 * Installation method: Executed from source package


Discussion:

Resolving patch:
diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py
--- a/pyqtgraph/exporters/SVGExporter.py
+++ b/pyqtgraph/exporters/SVGExporter.py
@@ -17,17 +17,28 @@ class SVGExporter(Exporter):
     
     def __init__(self, item):
         Exporter.__init__(self, item)
-        #tr = self.getTargetRect()
+        tr = self.getTargetRect()
+
+        if isinstance(item, QtGui.QGraphicsItem):
+            scene = item.scene()
+        else:
+            scene = item
+        bgbrush = scene.views()[0].backgroundBrush()
+        bg = bgbrush.color()
+        if bgbrush.style() == QtCore.Qt.NoBrush:
+            bg.setAlpha(0)
+
         self.params = Parameter(name='params', type='group', children=[
-            #{'name': 'width', 'type': 'float', 'value': tr.width(), 'limits': (0, None)},
-            #{'name': 'height', 'type': 'float', 'value': tr.height(), 'limits': (0, None)},
+            {'name': 'background', 'type': 'color', 'value': bg},
+            {'name': 'width', 'type': 'float', 'value': tr.width(), 'limits': (0, None)},
+            {'name': 'height', 'type': 'float', 'value': tr.height(), 'limits': (0, None)},
             #{'name': 'viewbox clipping', 'type': 'bool', 'value': True},
             #{'name': 'normalize coordinates', 'type': 'bool', 'value': True},
             {'name': 'scaling stroke', 'type': 'bool', 'value': False, 'tip': "If False, strokes are non-scaling, "
              "which means that they appear the same width on screen regardless of how they are scaled or how the view is zoomed."},
         ])
-        #self.params.param('width').sigValueChanged.connect(self.widthChanged)
-        #self.params.param('height').sigValueChanged.connect(self.heightChanged)
+        self.params.param('width').sigValueChanged.connect(self.widthChanged)
+        self.params.param('height').sigValueChanged.connect(self.heightChanged)
 
     def widthChanged(self):
         sr = self.getSourceRect()
@@ -51,6 +62,9 @@ def export(self, fileName=None, toBytes=False, copy=False):
         ## Instead, we will use Qt to generate SVG for each item independently,
         ## then manually reconstruct the entire document.
         options = {ch.name():ch.value() for ch in self.params.children()}
+        options['background'] = self.params['background']
+        options['width'] = self.params['width']
+        options['height'] = self.params['height']
         xml = generateSvg(self.item, options)
         
         if toBytes:
@@ -63,10 +77,10 @@ def export(self, fileName=None, toBytes=False, copy=False):
             with open(fileName, 'wb') as fh:
                 fh.write(asUnicode(xml).encode('utf-8'))
 
-
+# Includes space for extra attributes
 xmlHeader = """\
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  version="1.2" baseProfile="tiny">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  version="1.2" baseProfile="tiny"%s>
 <title>pyqtgraph SVG export</title>
 <desc>Generated with Qt and pyqtgraph</desc>
 <style>
@@ -100,7 +114,10 @@ def generateSvg(item, options={}):
     for d in defs:
         defsXml += d.toprettyxml(indent='    ')
     defsXml += "</defs>\n"
-    return xmlHeader + defsXml + node.toprettyxml(indent='    ') + "\n</svg>\n"
+    svgAttributes = ' viewBox ="0 0 %f %f"' % (options["width"], options["height"])
+    c = options['background']
+    backgroundtag = '<rect width="100%%" height="100%%" style="fill:rgba(%f, %f, %f, %d)" />\n' % (c.red(), c.blue(), c.green(), c.alpha()/255.0)
+    return (xmlHeader % svgAttributes) + backgroundtag + defsXml + node.toprettyxml(indent='    ') + "\n</svg>\n"
 
 
 def _generateItemSvg(item, nodes=None, root=None, options={}):


Test patch:
diff --git a/pyqtgraph/exporters/tests/test_svg.py b/pyqtgraph/exporters/tests/test_svg.py
--- a/pyqtgraph/exporters/tests/test_svg.py
+++ b/pyqtgraph/exporters/tests/test_svg.py
@@ -33,37 +33,42 @@ def test_plotscene():
 def test_simple():
     tempfilename = tempfile.NamedTemporaryFile(suffix='.svg').name
     print("using %s as a temporary file" % tempfilename)
-    scene = pg.QtGui.QGraphicsScene()
-    #rect = pg.QtGui.QGraphicsRectItem(0, 0, 100, 100)
-    #scene.addItem(rect)
-    #rect.setPos(20,20)
-    #rect.translate(50, 50)
-    #rect.rotate(30)
-    #rect.scale(0.5, 0.5)
     
-    #rect1 = pg.QtGui.QGraphicsRectItem(0, 0, 100, 100)
-    #rect1.setParentItem(rect)
-    #rect1.setFlag(rect1.ItemIgnoresTransformations)
-    #rect1.setPos(20, 20)
-    #rect1.scale(2,2)
+    view = pg.GraphicsView()
+    view.show()
+
+    scene = view.sceneObj
+
+    rect = pg.QtGui.QGraphicsRectItem(0, 0, 100, 100)
+    scene.addItem(rect)
+    rect.setPos(20,20)
+    rect.translate(50, 50)
+    rect.rotate(30)
+    rect.scale(0.5, 0.5)
+    
+    rect1 = pg.QtGui.QGraphicsRectItem(0, 0, 100, 100)
+    rect1.setParentItem(rect)
+    rect1.setFlag(rect1.ItemIgnoresTransformations)
+    rect1.setPos(20, 20)
+    rect1.scale(2,2)
     
-    #el1 = pg.QtGui.QGraphicsEllipseItem(0, 0, 100, 100)
-    #el1.setParentItem(rect1)
-    ##grp = pg.ItemGroup()
-    #grp.setParentItem(rect)
-    #grp.translate(200,0)
-    ##grp.rotate(30)
+    el1 = pg.QtGui.QGraphicsEllipseItem(0, 0, 100, 100)
+    el1.setParentItem(rect1)
+    grp = pg.ItemGroup()
+    grp.setParentItem(rect)
+    grp.translate(200,0)
+    grp.rotate(30)
     
-    #rect2 = pg.QtGui.QGraphicsRectItem(0, 0, 100, 25)
-    #rect2.setFlag(rect2.ItemClipsChildrenToShape)
-    #rect2.setParentItem(grp)
-    #rect2.setPos(0,25)
-    #rect2.rotate(30)
-    #el = pg.QtGui.QGraphicsEllipseItem(0, 0, 100, 50)
-    #el.translate(10,-5)
-    #el.scale(0.5,2)
+    rect2 = pg.QtGui.QGraphicsRectItem(0, 0, 100, 25)
+    rect2.setFlag(rect2.ItemClipsChildrenToShape)
+    rect2.setParentItem(grp)
+    rect2.setPos(0,25)
+    rect2.rotate(30)
+    el = pg.QtGui.QGraphicsEllipseItem(0, 0, 100, 50)
+    el.translate(10,-5)
+    el.scale(0.5,2)
 
-    #el.setParentItem(rect2)
+    el.setParentItem(rect2)
 
     grp2 = pg.ItemGroup()
     scene.addItem(grp2)