We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
CSV export broken
### Short description
Export CSV failed when the plot name has decode error characters.

### Code to reproduce
```python
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg

#QtGui.QApplication.setGraphicsSystem('raster')
app = QtGui.QApplication([])
win = pg.GraphicsLayoutWidget(show=True, title="Basic plotting examples")
win.resize(1000,600)
win.setWindowTitle('pyqtgraph example: Plotting')


pg.setConfigOptions(antialias=True)

pw = win.addPlot(title="Scatter plot, axis labels, log scale")
pw.addLegend()
pw .plot(np.random.normal(size=100), pen=(255,0,0), name="\u00A0下加热体")

QtGui.QApplication.instance().exec_()
```

### Expected behavior
Export CSV Success

### Real behavior
Export CSV Failed

```
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
c:\program files\python37\lib\site-packages\pyqtgraph\exporters\Exporter.py in fileSaveFinished(self, fileName)
     75                 fileName = fileName + '.' + selectedExt.lstrip('.')
     76
---> 77         self.export(fileName=fileName, **self.fileDialog.opts)
     78
     79     def getScene(self):

c:\program files\python37\lib\site-packages\pyqtgraph\exporters\CSVExporter.py in export(self, fileName)
     58
     59         with open(fileName, 'w') as fd:
---> 60             fd.write(sep.join(header) + '\n')
     61             i = 0
     62             numFormat = '%%0.%dg' % self.params['precision']

UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 1: illegal multibyte sequence
```

### Tested environment(s)

 * PyQtGraph version: 0.11.0.dev0+g2203933
 * Qt Python binding: PyQt5 5.13.2 Qt 5.13.2
 * Python version: Python 3.7.5 
 * NumPy version: 1.17.4
 * Operating system: Windows 7 X64
 * Installation method: pip  git+

### Additional context
I use "\u00A0" because i want to add some space before label name in the legend.
Could i use the csv export by "utf-8" but not "gbk" ?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyqtgraph/exporters/CSVExporter.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from ..Qt import QtGui, QtCore
3 from .Exporter import Exporter
4 from ..parametertree import Parameter
5 from .. import PlotItem
6 
7 __all__ = ['CSVExporter']
8     
9     
10 class CSVExporter(Exporter):
11     Name = "CSV from plot data"
12     windows = []
13     def __init__(self, item):
14         Exporter.__init__(self, item)
15         self.params = Parameter(name='params', type='group', children=[
16             {'name': 'separator', 'type': 'list', 'value': 'comma', 'values': ['comma', 'tab']},
17             {'name': 'precision', 'type': 'int', 'value': 10, 'limits': [0, None]},
18             {'name': 'columnMode', 'type': 'list', 'values': ['(x,y) per plot', '(x,y,y,y) for all plots']}
19         ])
20         
21     def parameters(self):
22         return self.params
23     
24     def export(self, fileName=None):
25         
26         if not isinstance(self.item, PlotItem):
27             raise Exception("Must have a PlotItem selected for CSV export.")
28         
29         if fileName is None:
30             self.fileSaveDialog(filter=["*.csv", "*.tsv"])
31             return
32 
33         data = []
34         header = []
35 
36         appendAllX = self.params['columnMode'] == '(x,y) per plot'
37 
38         for i, c in enumerate(self.item.curves):
39             cd = c.getData()
40             if cd[0] is None:
41                 continue
42             data.append(cd)
43             if hasattr(c, 'implements') and c.implements('plotData') and c.name() is not None:
44                 name = c.name().replace('"', '""') + '_'
45                 xName, yName = '"'+name+'x"', '"'+name+'y"'
46             else:
47                 xName = 'x%04d' % i
48                 yName = 'y%04d' % i
49             if appendAllX or i == 0:
50                 header.extend([xName, yName])
51             else:
52                 header.extend([yName])
53 
54         if self.params['separator'] == 'comma':
55             sep = ','
56         else:
57             sep = '\t'
58 
59         with open(fileName, 'w') as fd:
60             fd.write(sep.join(header) + '\n')
61             i = 0
62             numFormat = '%%0.%dg' % self.params['precision']
63             numRows = max([len(d[0]) for d in data])
64             for i in range(numRows):
65                 for j, d in enumerate(data):
66                     # write x value if this is the first column, or if we want
67                     # x for all rows
68                     if appendAllX or j == 0:
69                         if d is not None and i < len(d[0]):
70                             fd.write(numFormat % d[0][i] + sep)
71                         else:
72                             fd.write(' %s' % sep)
73 
74                     # write y value
75                     if d is not None and i < len(d[1]):
76                         fd.write(numFormat % d[1][i] + sep)
77                     else:
78                         fd.write(' %s' % sep)
79                 fd.write('\n')
80 
81 
82 CSVExporter.register()        
83                 
84         
85
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyqtgraph/exporters/CSVExporter.py b/pyqtgraph/exporters/CSVExporter.py
--- a/pyqtgraph/exporters/CSVExporter.py
+++ b/pyqtgraph/exporters/CSVExporter.py
@@ -3,6 +3,7 @@
 from .Exporter import Exporter
 from ..parametertree import Parameter
 from .. import PlotItem
+from ..python2_3 import asUnicode
 
 __all__ = ['CSVExporter']
     
@@ -57,7 +58,7 @@
             sep = '\t'
 
         with open(fileName, 'w') as fd:
-            fd.write(sep.join(header) + '\n')
+            fd.write(sep.join(map(asUnicode, header)) + '\n')
             i = 0
             numFormat = '%%0.%dg' % self.params['precision']
             numRows = max([len(d[0]) for d in data])

{"golden_diff": "diff --git a/pyqtgraph/exporters/CSVExporter.py b/pyqtgraph/exporters/CSVExporter.py\n--- a/pyqtgraph/exporters/CSVExporter.py\n+++ b/pyqtgraph/exporters/CSVExporter.py\n@@ -3,6 +3,7 @@\n from .Exporter import Exporter\n from ..parametertree import Parameter\n from .. import PlotItem\n+from ..python2_3 import asUnicode\n \n __all__ = ['CSVExporter']\n     \n@@ -57,7 +58,7 @@\n             sep = '\\t'\n \n         with open(fileName, 'w') as fd:\n-            fd.write(sep.join(header) + '\\n')\n+            fd.write(sep.join(map(asUnicode, header)) + '\\n')\n             i = 0\n             numFormat = '%%0.%dg' % self.params['precision']\n             numRows = max([len(d[0]) for d in data])\n", "issue": "CSV export broken\n### Short description\r\nExport CSV failed when the plot name has decode error characters.\r\n\r\n### Code to reproduce\r\n```python\r\nfrom pyqtgraph.Qt import QtGui, QtCore\r\nimport numpy as np\r\nimport pyqtgraph as pg\r\n\r\n#QtGui.QApplication.setGraphicsSystem('raster')\r\napp = QtGui.QApplication([])\r\nwin = pg.GraphicsLayoutWidget(show=True, title=\"Basic plotting examples\")\r\nwin.resize(1000,600)\r\nwin.setWindowTitle('pyqtgraph example: Plotting')\r\n\r\n\r\npg.setConfigOptions(antialias=True)\r\n\r\npw = win.addPlot(title=\"Scatter plot, axis labels, log scale\")\r\npw.addLegend()\r\npw .plot(np.random.normal(size=100), pen=(255,0,0), name=\"\\u00A0\u4e0b\u52a0\u70ed\u4f53\")\r\n\r\nQtGui.QApplication.instance().exec_()\r\n```\r\n\r\n### Expected behavior\r\nExport CSV Success\r\n\r\n### Real behavior\r\nExport CSV Failed\r\n\r\n```\r\n---------------------------------------------------------------------------\r\nUnicodeEncodeError                        Traceback (most recent call last)\r\nc:\\program files\\python37\\lib\\site-packages\\pyqtgraph\\exporters\\Exporter.py in fileSaveFinished(self, fileName)\r\n     75                 fileName = fileName + '.' + selectedExt.lstrip('.')\r\n     76\r\n---> 77         self.export(fileName=fileName, **self.fileDialog.opts)\r\n     78\r\n     79     def getScene(self):\r\n\r\nc:\\program files\\python37\\lib\\site-packages\\pyqtgraph\\exporters\\CSVExporter.py in export(self, fileName)\r\n     58\r\n     59         with open(fileName, 'w') as fd:\r\n---> 60             fd.write(sep.join(header) + '\\n')\r\n     61             i = 0\r\n     62             numFormat = '%%0.%dg' % self.params['precision']\r\n\r\nUnicodeEncodeError: 'gbk' codec can't encode character '\\xa0' in position 1: illegal multibyte sequence\r\n```\r\n\r\n### Tested environment(s)\r\n\r\n * PyQtGraph version: 0.11.0.dev0+g2203933\r\n * Qt Python binding: PyQt5 5.13.2 Qt 5.13.2\r\n * Python version: Python 3.7.5 \r\n * NumPy version: 1.17.4\r\n * Operating system: Windows 7 X64\r\n * Installation method: pip  git+\r\n\r\n### Additional context\r\nI use \"\\u00A0\" because i want to add some space before label name in the legend.\r\nCould i use the csv export by \"utf-8\" but not \"gbk\" ?\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom ..Qt import QtGui, QtCore\nfrom .Exporter import Exporter\nfrom ..parametertree import Parameter\nfrom .. import PlotItem\n\n__all__ = ['CSVExporter']\n    \n    \nclass CSVExporter(Exporter):\n    Name = \"CSV from plot data\"\n    windows = []\n    def __init__(self, item):\n        Exporter.__init__(self, item)\n        self.params = Parameter(name='params', type='group', children=[\n            {'name': 'separator', 'type': 'list', 'value': 'comma', 'values': ['comma', 'tab']},\n            {'name': 'precision', 'type': 'int', 'value': 10, 'limits': [0, None]},\n            {'name': 'columnMode', 'type': 'list', 'values': ['(x,y) per plot', '(x,y,y,y) for all plots']}\n        ])\n        \n    def parameters(self):\n        return self.params\n    \n    def export(self, fileName=None):\n        \n        if not isinstance(self.item, PlotItem):\n            raise Exception(\"Must have a PlotItem selected for CSV export.\")\n        \n        if fileName is None:\n            self.fileSaveDialog(filter=[\"*.csv\", \"*.tsv\"])\n            return\n\n        data = []\n        header = []\n\n        appendAllX = self.params['columnMode'] == '(x,y) per plot'\n\n        for i, c in enumerate(self.item.curves):\n            cd = c.getData()\n            if cd[0] is None:\n                continue\n            data.append(cd)\n            if hasattr(c, 'implements') and c.implements('plotData') and c.name() is not None:\n                name = c.name().replace('\"', '\"\"') + '_'\n                xName, yName = '\"'+name+'x\"', '\"'+name+'y\"'\n            else:\n                xName = 'x%04d' % i\n                yName = 'y%04d' % i\n            if appendAllX or i == 0:\n                header.extend([xName, yName])\n            else:\n                header.extend([yName])\n\n        if self.params['separator'] == 'comma':\n            sep = ','\n        else:\n            sep = '\\t'\n\n        with open(fileName, 'w') as fd:\n            fd.write(sep.join(header) + '\\n')\n            i = 0\n            numFormat = '%%0.%dg' % self.params['precision']\n            numRows = max([len(d[0]) for d in data])\n            for i in range(numRows):\n                for j, d in enumerate(data):\n                    # write x value if this is the first column, or if we want\n                    # x for all rows\n                    if appendAllX or j == 0:\n                        if d is not None and i < len(d[0]):\n                            fd.write(numFormat % d[0][i] + sep)\n                        else:\n                            fd.write(' %s' % sep)\n\n                    # write y value\n                    if d is not None and i < len(d[1]):\n                        fd.write(numFormat % d[1][i] + sep)\n                    else:\n                        fd.write(' %s' % sep)\n                fd.write('\\n')\n\n\nCSVExporter.register()        \n                \n        \n", "path": "pyqtgraph/exporters/CSVExporter.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom ..Qt import QtGui, QtCore\nfrom .Exporter import Exporter\nfrom ..parametertree import Parameter\nfrom .. import PlotItem\nfrom ..python2_3 import asUnicode\n\n__all__ = ['CSVExporter']\n    \n    \nclass CSVExporter(Exporter):\n    Name = \"CSV from plot data\"\n    windows = []\n    def __init__(self, item):\n        Exporter.__init__(self, item)\n        self.params = Parameter(name='params', type='group', children=[\n            {'name': 'separator', 'type': 'list', 'value': 'comma', 'values': ['comma', 'tab']},\n            {'name': 'precision', 'type': 'int', 'value': 10, 'limits': [0, None]},\n            {'name': 'columnMode', 'type': 'list', 'values': ['(x,y) per plot', '(x,y,y,y) for all plots']}\n        ])\n        \n    def parameters(self):\n        return self.params\n    \n    def export(self, fileName=None):\n        \n        if not isinstance(self.item, PlotItem):\n            raise Exception(\"Must have a PlotItem selected for CSV export.\")\n        \n        if fileName is None:\n            self.fileSaveDialog(filter=[\"*.csv\", \"*.tsv\"])\n            return\n\n        data = []\n        header = []\n\n        appendAllX = self.params['columnMode'] == '(x,y) per plot'\n\n        for i, c in enumerate(self.item.curves):\n            cd = c.getData()\n            if cd[0] is None:\n                continue\n            data.append(cd)\n            if hasattr(c, 'implements') and c.implements('plotData') and c.name() is not None:\n                name = c.name().replace('\"', '\"\"') + '_'\n                xName, yName = '\"'+name+'x\"', '\"'+name+'y\"'\n            else:\n                xName = 'x%04d' % i\n                yName = 'y%04d' % i\n            if appendAllX or i == 0:\n                header.extend([xName, yName])\n            else:\n                header.extend([yName])\n\n        if self.params['separator'] == 'comma':\n            sep = ','\n        else:\n            sep = '\\t'\n\n        with open(fileName, 'w') as fd:\n            fd.write(sep.join(map(asUnicode, header)) + '\\n')\n            i = 0\n            numFormat = '%%0.%dg' % self.params['precision']\n            numRows = max([len(d[0]) for d in data])\n            for i in range(numRows):\n                for j, d in enumerate(data):\n                    # write x value if this is the first column, or if we want\n                    # x for all rows\n                    if appendAllX or j == 0:\n                        if d is not None and i < len(d[0]):\n                            fd.write(numFormat % d[0][i] + sep)\n                        else:\n                            fd.write(' %s' % sep)\n\n                    # write y value\n                    if d is not None and i < len(d[1]):\n                        fd.write(numFormat % d[1][i] + sep)\n                    else:\n                        fd.write(' %s' % sep)\n                fd.write('\\n')\n\n\nCSVExporter.register()        \n                \n        \n", "path": "pyqtgraph/exporters/CSVExporter.py"}]}