Index: src/sas/qtgui/MainWindow/DataExplorer.py
===================================================================
--- src/sas/qtgui/MainWindow/DataExplorer.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/MainWindow/DataExplorer.py	(revision d48cc19810059080c3b51d9b2c82196981cbfe1f)
@@ -433,4 +433,23 @@
         self.chkBatch.setEnabled(self.parent.perspective().allowBatch())
 
+    def displayData(self, data_list):
+        """
+        Forces display of charts for the given filename
+        """
+        # Assure no multiple plots for the same ID
+        plot_to_show = data_list[0]
+        for plot in PlotHelper.currentPlots():
+            if plot == plot_to_show.id:
+                return
+
+        new_plot = Plotter(self)
+        # Now query the model item for available plots
+        filename = plot_to_show.filename
+        model = self.model if plot_to_show.is_data else self.theory_model
+        plots = GuiUtils.plotsFromFilename(filename, model)
+        for plot in plots:
+            new_plot.plot(plot)
+        self.plotAdd(new_plot)
+
     def newPlot(self):
         """
Index: src/sas/qtgui/MainWindow/GuiManager.py
===================================================================
--- src/sas/qtgui/MainWindow/GuiManager.py	(revision 28a09b01c106f3e406a519f370a0c81b6cf9ee18)
+++ src/sas/qtgui/MainWindow/GuiManager.py	(revision d48cc19810059080c3b51d9b2c82196981cbfe1f)
@@ -335,4 +335,5 @@
         self.communicate.perspectiveChangedSignal.connect(self.perspectiveChanged)
         self.communicate.updateTheoryFromPerspectiveSignal.connect(self.updateTheoryFromPerspective)
+        self.communicate.plotRequestedSignal.connect(self.showPlot)
 
     def addTriggers(self):
@@ -727,4 +728,9 @@
         self.filesWidget.updateTheoryFromPerspective(index)
 
-
-
+    def showPlot(self, plot):
+        """
+        Pass the show plot request to the data explorer
+        """
+        if hasattr(self, "filesWidget"):
+            self.filesWidget.displayData(plot)
+
Index: src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py	(revision 180bd545166c0e0d674354e554dec53998b492c6)
+++ src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py	(revision d48cc19810059080c3b51d9b2c82196981cbfe1f)
@@ -262,4 +262,5 @@
         residuals.y = -y
     else:
+        # TODO: fix case where applying new data from file on top of existing model data
         y = (fn - gn[index][0]) / en
         residuals.y = y
Index: src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision 61a92d4c3e2e9b0410555517d59b1e8503c98ff4)
+++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py	(revision d48cc19810059080c3b51d9b2c82196981cbfe1f)
@@ -74,4 +74,7 @@
         self.weighting = 0
 
+        # Data for chosen model
+        self.model_data = None
+
         # Which tab is this widget displayed in?
         self.tab_id = id
@@ -250,5 +253,5 @@
         """
         self.cmdFit.setEnabled(False)
-        self.cmdPlot.setEnabled(True)
+        self.cmdPlot.setEnabled(False)
         self.options_widget.cmdComputePoints.setVisible(False) # probably redundant
         self.chkPolydispersity.setEnabled(True)
@@ -305,10 +308,15 @@
         self.has_error_column = False
 
+        # Set enablement on calculate/plot
+        self.cmdPlot.setEnabled(True)
+
         # SasModel -> QModel
         self.SASModelToQModel(model)
 
         if self.data_is_loaded:
+            self.cmdPlot.setText("Show Plot")
             self.calculateQGridForModel()
         else:
+            self.cmdPlot.setText("Calculate")
             # Create default datasets if no data passed
             self.createDefaultDataset()
@@ -569,7 +577,25 @@
         Plot the current set of data
         """
+        # Regardless of previous state, this should now be `plot show` functionality only
+        self.cmdPlot.setText("Show Plot")
+        self.recalculatePlotData()
+        self.showPlot()
+
+    def recalculatePlotData(self):
+        """
+        Generate a new dataset for model
+        """
         if not self.data_is_loaded:
             self.createDefaultDataset()
         self.calculateQGridForModel()
+
+    def showPlot(self):
+        """
+        Show the current plot in MPL
+        """
+        # Show the chart if ready
+        data_to_show = self.data if self.data_is_loaded else self.model_data
+        if data_to_show is not None:
+            self.communicate.plotRequestedSignal.emit([data_to_show])
 
     def onOptionsUpdate(self):
@@ -582,5 +608,5 @@
         self.lblMinRangeDef.setText(str(self.q_range_min))
         self.lblMaxRangeDef.setText(str(self.q_range_max))
-        self.onPlot()
+        self.recalculatePlotData()
 
     def setDefaultStructureCombo(self):
@@ -766,5 +792,5 @@
         # Force the chart update when actual parameters changed
         if model_column == 1:
-            self.onPlot()
+            self.recalculatePlotData()
 
     def checkboxSelected(self, item):
@@ -891,6 +917,7 @@
         Plot the current 1D data
         """
-        fitted_plot = self.logic.new1DPlot(return_data, self.tab_id)
-        self.calculateResiduals(fitted_plot)
+        fitted_data = self.logic.new1DPlot(return_data, self.tab_id)
+        self.calculateResiduals(fitted_data)
+        self.model_data = fitted_data
 
     def complete2D(self, return_data):
@@ -900,4 +927,5 @@
         fitted_data = self.logic.new2DPlot(return_data)
         self.calculateResiduals(fitted_data)
+        self.model_data = fitted_data
 
     def calculateResiduals(self, fitted_data):
@@ -914,4 +942,6 @@
         self.lblChi2Value.setText(chi2_repr)
 
+        self.communicate.plotUpdateSignal.emit([fitted_data])
+
         # Plot residuals if actual data
         if self.data_is_loaded:
@@ -920,6 +950,4 @@
             self.createNewIndex(residuals_plot)
             self.communicate.plotUpdateSignal.emit([residuals_plot])
-
-        self.communicate.plotUpdateSignal.emit([fitted_data])
 
     def calcException(self, etype, value, tb):
Index: src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py	(revision d48cc19810059080c3b51d9b2c82196981cbfe1f)
@@ -1,4 +1,5 @@
 import sys
 import unittest
+import time
 
 from PyQt4 import QtGui
@@ -21,6 +22,5 @@
 
 class dummy_manager(object):
-    def communicate(self):
-        return Communicate()
+    communicate = Communicate()
 
 class FittingWidgetTest(unittest.TestCase):
@@ -80,8 +80,7 @@
         self.assertFalse(widget_with_data.acceptsData())
 
-    def notestSelectModel(self):
+    def testSelectModel(self):
         """
         Test if models have been loaded properly
-        :return:
         """
         fittingWindow =  self.widget
@@ -280,5 +279,5 @@
         pass
 
-    def notestCreateTheoryIndex(self):
+    def testCreateTheoryIndex(self):
         """
         Test the data->QIndex conversion
@@ -292,10 +291,11 @@
 
         # Create the index
-        self.widget.createTheoryIndex()
-
-        # Check the signal sent
-        print spy
-
-        # Check the index
+        self.widget.createTheoryIndex(Data1D(x=[1,2], y=[1,2]))
+
+        # Make sure the signal has been emitted
+        self.assertEqual(spy.count(), 1)
+
+        # Check the argument type
+        self.assertIsInstance(spy.called()[0]['args'][0], QtGui.QStandardItem)
 
     def testCalculateQGridForModel(self):
@@ -305,23 +305,38 @@
         # Mock the thread creation
         threads.deferToThread = MagicMock()
+        # Model for theory
+        self.widget.SASModelToQModel("cylinder")
         # Call the tested method
         self.widget.calculateQGridForModel()
+        time.sleep(1)
         # Test the mock
         self.assertTrue(threads.deferToThread.called)
         self.assertEqual(threads.deferToThread.call_args_list[0][0][0].__name__, "compute")
 
-    def testComplete1D(self):
-        """
-        Check that a new 1D plot is generated
-        """
-        # TODO when chisqr method coded
-        pass
-
-    def testComplete2D(self):
-        """
-        Check that a new 2D plot is generated
-        """
-        # TODO when chisqr method coded
-        pass
+    def testCalculateResiduals(self):
+        """
+        Check that the residuals are calculated and plots updated
+        """
+        test_data = Data1D(x=[1,2], y=[1,2])
+
+        # Model for theory
+        self.widget.SASModelToQModel("cylinder")
+        # Invoke the tested method
+        self.widget.calculateResiduals(test_data)
+        # Check the Chi2 value - should be undetermined
+        self.assertEqual(self.widget.lblChi2Value.text(), '---')
+
+        # Force same data into logic
+        self.widget.logic.data = test_data
+        self.widget.calculateResiduals(test_data)
+        # Now, the difference is 0, as data is the same
+        self.assertEqual(self.widget.lblChi2Value.text(), '0')
+
+        # Change data
+        test_data_2 = Data1D(x=[1,2], y=[2.1,3.49])
+        self.widget.logic.data = test_data_2
+        self.widget.calculateResiduals(test_data)
+        # Now, the difference is non-zero
+        self.assertEqual(float(self.widget.lblChi2Value.text()), 1.715)
 
     def testSetPolyModel(self):
@@ -410,4 +425,77 @@
         self.assertEqual(self.widget._model_model.rowCount(), last_row)
 
+    def testPlotTheory(self):
+        """
+        See that theory item can produce a chart
+        """
+        # By default, the compute/plot button is disabled
+        self.assertFalse(self.widget.cmdPlot.isEnabled())
+        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
+
+        # Assign a model
+        self.widget.show()
+        # Change the category index so we have a model available
+        category_index = self.widget.cbCategory.findText("Sphere")
+        self.widget.cbCategory.setCurrentIndex(category_index)
+
+        # Check the enablement/text
+        self.assertTrue(self.widget.cmdPlot.isEnabled())
+        self.assertEqual(self.widget.cmdPlot.text(), 'Calculate')
+
+        # Spying on plot update signal
+        spy = QtSignalSpy(self.widget, self.widget.communicate.plotRequestedSignal)
+
+        # Press Calculate
+        QtTest.QTest.mouseClick(self.widget.cmdPlot, QtCore.Qt.LeftButton)
+
+        # Observe cmdPlot caption change
+        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
+
+        # Make sure the signal has NOT been emitted
+        self.assertEqual(spy.count(), 0)
+
+        # Click again
+        QtTest.QTest.mouseClick(self.widget.cmdPlot, QtCore.Qt.LeftButton)
+
+        # This time, we got the update signal
+        self.assertEqual(spy.count(), 0)
+
+    def testPlotData(self):
+        """
+        See that data item can produce a chart
+        """
+        # By default, the compute/plot button is disabled
+        self.assertFalse(self.widget.cmdPlot.isEnabled())
+        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
+
+        self.widget.show()
+
+        # Set data
+        test_data = Data1D(x=[1,2], y=[1,2])
+
+        # Force same data into logic
+        self.widget.logic.data = test_data
+        self.widget.data_is_loaded = True
+
+        # Change the category index so we have a model available
+        category_index = self.widget.cbCategory.findText("Sphere")
+        self.widget.cbCategory.setCurrentIndex(category_index)
+
+        # Check the enablement/text
+        self.assertTrue(self.widget.cmdPlot.isEnabled())
+        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
+
+        # Spying on plot update signal
+        spy = QtSignalSpy(self.widget, self.widget.communicate.plotRequestedSignal)
+
+        # Press Calculate
+        QtTest.QTest.mouseClick(self.widget.cmdPlot, QtCore.Qt.LeftButton)
+
+        # Observe cmdPlot caption did not change
+        self.assertEqual(self.widget.cmdPlot.text(), 'Show Plot')
+
+        # Make sure the signal has been emitted == new plot
+        self.assertEqual(spy.count(), 1)
+
 
 if __name__ == "__main__":
Index: src/sas/qtgui/Utilities/GuiUtils.py
===================================================================
--- src/sas/qtgui/Utilities/GuiUtils.py	(revision 83eb5208b8acb86b064162274de583670f72da47)
+++ src/sas/qtgui/Utilities/GuiUtils.py	(revision d48cc19810059080c3b51d9b2c82196981cbfe1f)
@@ -229,5 +229,5 @@
     # New plot requested from the GUI manager
     # Old "NewPlotEvent"
-    plotRequestedSignal = QtCore.pyqtSignal(str)
+    plotRequestedSignal = QtCore.pyqtSignal(list)
 
     # Plot update requested from a perspective
@@ -323,4 +323,26 @@
     item.appendRow(object_item)
 
+def plotsFromFilename(filename, model_item):
+    """
+    Returns the list of plots for the item with text=filename in the model
+    """
+    assert isinstance(model_item, QtGui.QStandardItemModel)
+    assert isinstance(filename, basestring)
+
+    plot_data = []
+    # Iterate over model looking for named items
+    for index in range(model_item.rowCount()):
+        item = model_item.item(index)
+        if str(item.text()) == filename:
+            # TODO: assure item type is correct (either data1/2D or Plotter)
+            plot_data.append(item.child(0).data().toPyObject())
+        # Going 1 level deeper only
+        for index_2 in range(item.rowCount()):
+            item_2 = item.child(index_2)
+            if item_2 and item_2.isCheckable():
+                # TODO: assure item type is correct (either data1/2D or Plotter)
+                plot_data.append(item_2.child(0).data().toPyObject())
+
+    return plot_data
 
 def plotsFromCheckedItems(model_item):
