Repository: pyqtgraph/pyqtgraph

Issue:
Matplotlib exporter scientific notation bugfix
Fix setting labels and values in case of plots which use scientific notation.

Solves issue #1050 


Discussion:
Hey @penkod, I can go ahead and build from your commits to implement the requested changes. If you prefer to do it yourself, let me know. Thanks for the contribution in any case.
Hi @ixjlyons. At the time being, I unable to do the necessary changes + the tests, so of course, if you wish you can implement the necessary changes yourself. 

Resolving patch:
diff --git a/pyqtgraph/exporters/Matplotlib.py b/pyqtgraph/exporters/Matplotlib.py
--- a/pyqtgraph/exporters/Matplotlib.py
+++ b/pyqtgraph/exporters/Matplotlib.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 from ..Qt import QtGui, QtCore
 from .Exporter import Exporter
 from .. import PlotItem
@@ -31,6 +32,7 @@
 class MatplotlibExporter(Exporter):
     Name = "Matplotlib Window"
     windows = []
+
     def __init__(self, item):
         Exporter.__init__(self, item)
         
@@ -55,58 +57,70 @@ def cleanAxes(self, axl):
                 ax.xaxis.set_ticks_position('bottom')
     
     def export(self, fileName=None):
+        if not isinstance(self.item, PlotItem):
+            raise Exception("MatplotlibExporter currently only works with PlotItem")
+    
+        mpw = MatplotlibWindow()
+        MatplotlibExporter.windows.append(mpw)
+
+        fig = mpw.getFigure()
+
+        xax = self.item.getAxis('bottom')
+        yax = self.item.getAxis('left')
         
-        if isinstance(self.item, PlotItem):
-            mpw = MatplotlibWindow()
-            MatplotlibExporter.windows.append(mpw)
+        # get labels from the graphic item
+        xlabel = xax.label.toPlainText()
+        ylabel = yax.label.toPlainText()
+        title = self.item.titleLabel.text
+
+        # if axes use autoSIPrefix, scale the data so mpl doesn't add its own
+        # scale factor label
+        xscale = yscale = 1.0
+        if xax.autoSIPrefix:
+            xscale = xax.autoSIPrefixScale
+        if yax.autoSIPrefix:
+            yscale = yax.autoSIPrefixScale
 
-            stdFont = 'Arial'
+        ax = fig.add_subplot(111, title=title)
+        ax.clear()
+        self.cleanAxes(ax)
+        for item in self.item.curves:
+            x, y = item.getData()
+            x = x * xscale
+            y = y * yscale
+
+            opts = item.opts
+            pen = fn.mkPen(opts['pen'])
+            if pen.style() == QtCore.Qt.NoPen:
+                linestyle = ''
+            else:
+                linestyle = '-'
+            color = tuple([c/255. for c in fn.colorTuple(pen.color())])
+            symbol = opts['symbol']
+            if symbol == 't':
+                symbol = '^'
+            symbolPen = fn.mkPen(opts['symbolPen'])
+            symbolBrush = fn.mkBrush(opts['symbolBrush'])
+            markeredgecolor = tuple([c/255. for c in fn.colorTuple(symbolPen.color())])
+            markerfacecolor = tuple([c/255. for c in fn.colorTuple(symbolBrush.color())])
+            markersize = opts['symbolSize']
             
-            fig = mpw.getFigure()
+            if opts['fillLevel'] is not None and opts['fillBrush'] is not None:
+                fillBrush = fn.mkBrush(opts['fillBrush'])
+                fillcolor = tuple([c/255. for c in fn.colorTuple(fillBrush.color())])
+                ax.fill_between(x=x, y1=y, y2=opts['fillLevel'], facecolor=fillcolor)
             
-            # get labels from the graphic item
-            xlabel = self.item.axes['bottom']['item'].label.toPlainText()
-            ylabel = self.item.axes['left']['item'].label.toPlainText()
-            title = self.item.titleLabel.text
+            pl = ax.plot(x, y, marker=symbol, color=color, linewidth=pen.width(), 
+                    linestyle=linestyle, markeredgecolor=markeredgecolor, markerfacecolor=markerfacecolor,
+                    markersize=markersize)
 
-            ax = fig.add_subplot(111, title=title)
-            ax.clear()
-            self.cleanAxes(ax)
-            #ax.grid(True)
-            for item in self.item.curves:
-                x, y = item.getData()
-                opts = item.opts
-                pen = fn.mkPen(opts['pen'])
-                if pen.style() == QtCore.Qt.NoPen:
-                    linestyle = ''
-                else:
-                    linestyle = '-'
-                color = tuple([c/255. for c in fn.colorTuple(pen.color())])
-                symbol = opts['symbol']
-                if symbol == 't':
-                    symbol = '^'
-                symbolPen = fn.mkPen(opts['symbolPen'])
-                symbolBrush = fn.mkBrush(opts['symbolBrush'])
-                markeredgecolor = tuple([c/255. for c in fn.colorTuple(symbolPen.color())])
-                markerfacecolor = tuple([c/255. for c in fn.colorTuple(symbolBrush.color())])
-                markersize = opts['symbolSize']
-                
-                if opts['fillLevel'] is not None and opts['fillBrush'] is not None:
-                    fillBrush = fn.mkBrush(opts['fillBrush'])
-                    fillcolor = tuple([c/255. for c in fn.colorTuple(fillBrush.color())])
-                    ax.fill_between(x=x, y1=y, y2=opts['fillLevel'], facecolor=fillcolor)
-                
-                pl = ax.plot(x, y, marker=symbol, color=color, linewidth=pen.width(), 
-                        linestyle=linestyle, markeredgecolor=markeredgecolor, markerfacecolor=markerfacecolor,
-                        markersize=markersize)
-                xr, yr = self.item.viewRange()
-                ax.set_xbound(*xr)
-                ax.set_ybound(*yr)
-            ax.set_xlabel(xlabel)  # place the labels.
-            ax.set_ylabel(ylabel)
-            mpw.draw()
-        else:
-            raise Exception("Matplotlib export currently only works with plot items")
+            xr, yr = self.item.viewRange()
+            ax.set_xbound(xr[0]*xscale, xr[1]*xscale)
+            ax.set_ybound(yr[0]*yscale, yr[1]*yscale)
+
+        ax.set_xlabel(xlabel)  # place the labels.
+        ax.set_ylabel(ylabel)
+        mpw.draw()
                 
 MatplotlibExporter.register()        
         


Test patch:
diff --git a/pyqtgraph/exporters/tests/test_matplotlib.py b/pyqtgraph/exporters/tests/test_matplotlib.py
new file mode 100644
--- /dev/null
+++ b/pyqtgraph/exporters/tests/test_matplotlib.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+import pytest
+import pyqtgraph as pg
+from pyqtgraph.exporters import MatplotlibExporter
+pytest.importorskip("matplotlib")
+
+app = pg.mkQApp()
+
+
+def test_MatplotlibExporter():
+    plt = pg.plot()
+
+    # curve item
+    plt.plot([0, 1, 2], [0, 1, 2])
+    # scatter item
+    plt.plot([0, 1, 2], [1, 2, 3], pen=None, symbolBrush='r')
+    # curve + scatter
+    plt.plot([0, 1, 2], [2, 3, 4], pen='k', symbolBrush='r')
+
+    exp = MatplotlibExporter(plt.getPlotItem())
+    exp.export()
+
+
+def test_MatplotlibExporter_nonplotitem():
+    # attempting to export something other than a PlotItem raises an exception
+    plt = pg.plot()
+    plt.plot([0, 1, 2], [2, 3, 4])
+    exp = MatplotlibExporter(plt.getPlotItem().getViewBox())
+    with pytest.raises(Exception):
+        exp.export()
+
+
+@pytest.mark.parametrize('scale', [1e10, 1e-9])
+def test_MatplotlibExporter_siscale(scale):
+    # coarse test to verify that plot data is scaled before export when
+    # autoSIPrefix is in effect (so mpl doesn't add its own multiplier label)
+    plt = pg.plot([0, 1, 2], [(i+1)*scale for i in range(3)])
+    # set the label so autoSIPrefix works
+    plt.setLabel('left', 'magnitude')
+    exp = MatplotlibExporter(plt.getPlotItem())
+    exp.export()
+
+    mpw = MatplotlibExporter.windows[-1]
+    fig = mpw.getFigure()
+    ymin, ymax = fig.axes[0].get_ylim()
+
+    if scale < 1:
+        assert ymax > scale
+    else:
+        assert ymax < scale