Index: src/sans/fit/BumpsFitting.py
===================================================================
--- src/sans/fit/BumpsFitting.py	(revision 85f17f6bb5b70f80e5a85bdff8c094ee719a425e)
+++ src/sans/fit/BumpsFitting.py	(revision ed4aef2412e82813a3c69fc3d050687b22a157ad)
@@ -16,6 +16,8 @@
         self.handler = handler
         self.max_step = max_step
+
     def config_history(self, history):
         history.requires(time=1, value=2, point=1, step=1)
+
     def __call__(self, history):
         self.handler.progress(history.step[0], self.max_step)
@@ -23,4 +25,26 @@
             self.handler.improvement()
         self.handler.update_fit()
+
+class ConvergenceMonitor(object):
+    """
+    ConvergenceMonitor contains population summary statistics to show progress
+    of the fit.  This is a list [ (best, 0%, 25%, 50%, 75%, 100%) ] or
+    just a list [ (best, ) ] if population size is 1.
+    """
+    def __init__(self):
+        self.convergence = []
+
+    def config_history(self, history):
+        history.requires(value=1, population_values=1)
+
+    def __call__(self, history):
+        best = history.value[0]
+        try:
+            p = history.population_values[0]
+            n,p = len(p), numpy.sort(p)
+            QI,Qmid, = int(0.2*n),int(0.5*n)
+            self.convergence.append((best, p[0],p[QI],p[Qmid],p[-1-QI],p[-1]))
+        except:
+            self.convergence.append((best, ))
 
 class SasProblem(object):
@@ -257,5 +281,5 @@
             run_bumps(problem, result, ftol,
                       handler, curr_thread, msg_q)
-        else:
+        else: # scipy levenburg marquardt
             problem = SasProblem(param_list=self.param_list,
                                  model=model.model,
@@ -292,4 +316,5 @@
     if 'monitors' not in options:
         options['monitors'] = [BumpsMonitor(handler, max_steps)]
+    options['monitors'] += [ ConvergenceMonitor() ]
     options['ftol'] = ftol
     fitdriver = fitters.FitDriver(fitclass, problem=problem,
@@ -312,4 +337,10 @@
     result.success = True
     result.theory = problem.theory
+    # For the convergence plot
+    pop = numpy.asarray(options['monitors'][-1].convergence)
+    result.convergence = 2*pop/problem.dof
+    # Bumps uncertainty state
+    try: result.uncertainty_state = fitdriver.fitter.state
+    except AttributeError: pass
 
 def run_levenburg_marquardt(problem, result, ftol):
Index: src/sans/perspectives/fitting/fitting.py
===================================================================
--- src/sans/perspectives/fitting/fitting.py	(revision 644ca73017baa0189f6424c93e070248941b265a)
+++ src/sans/perspectives/fitting/fitting.py	(revision ed4aef2412e82813a3c69fc3d050687b22a157ad)
@@ -36,4 +36,6 @@
 from .fitproblem import FitProblemDictionary
 from .fitpanel import FitPanel
+from .resultpanel import ResultPanel, PlotResultEvent
+
 from .fit_thread import FitThread
 from .pagestate import Reader
@@ -221,4 +223,10 @@
         self.bumps_options_menu = self.menu1.FindItemById(self.id_bumps_options)
         self.bumps_options_menu.Enable(True)
+
+        self.id_result_panel = wx.NewId()
+        self.menu1.AppendItem(self.id_result_panel, "Fit Results",
+                              "Show fit results panel")
+        wx.EVT_MENU(owner, self.id_result_panel,
+                    lambda ev: self.result_frame.Show(not self.result_frame.IsShown()))
         self.menu1.AppendSeparator()
         
@@ -525,4 +533,8 @@
         self.perspective = []
         self.perspective.append(self.fit_panel.window_name)
+
+        self.result_frame = MDIFrame(self.parent, None, ResultPanel.window_caption, (220, 200))
+        self.result_panel = ResultPanel(parent=self.result_frame, manager=self)
+        self.perspective.append(self.result_panel.window_name)
        
         #index number to create random model name
@@ -539,4 +551,5 @@
         #Send the fitting panel to guiframe
         self.mypanels.append(self.fit_panel)
+        self.mypanels.append(self.result_panel)
         return self.mypanels
     
@@ -1589,4 +1602,5 @@
         wx.PostEvent(self.parent, StatusEvent(status=msg, info="info",
                                                       type="stop"))
+        wx.PostEvent(self.result_panel, PlotResultEvent(result=result))
         # reset fit_engine if changed by simul_fit
         if self._fit_engine != self._gui_engine:
Index: src/sans/perspectives/fitting/resultpanel.py
===================================================================
--- src/sans/perspectives/fitting/resultpanel.py	(revision ed4aef2412e82813a3c69fc3d050687b22a157ad)
+++ src/sans/perspectives/fitting/resultpanel.py	(revision ed4aef2412e82813a3c69fc3d050687b22a157ad)
@@ -0,0 +1,85 @@
+"""
+FitPanel class contains fields allowing to fit  models and  data
+
+:note: For Fit to be performed the user should check at least one parameter
+    on fit Panel window.
+   
+"""
+import wx
+import wx.lib.newevent
+from wx.aui import AuiNotebook as Notebook
+
+from sans.guiframe.panel_base import PanelBase
+from sans.guiframe.events import StatusEvent
+
+(PlotResultEvent, EVT_PLOT_RESULT) = wx.lib.newevent.NewEvent()
+
+
+class ResultPanel(Notebook, PanelBase):
+    """
+    FitPanel class contains fields allowing to fit  models and  data
+    
+    :note: For Fit to be performed the user should check at least one parameter
+        on fit Panel window.
+       
+    """
+    ## Internal name for the AUI manager
+    window_name = "Result panel"
+    ## Title to appear on top of the window
+    window_caption = "Result Panel"
+    CENTER_PANE = True
+    
+    def __init__(self, parent, manager=None, *args, **kwargs):
+        """
+        """
+        style = ((wx.aui.AUI_NB_WINDOWLIST_BUTTON
+                 |wx.aui.AUI_NB_DEFAULT_STYLE
+                 |wx.CLIP_CHILDREN)
+                 & ~wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
+        Notebook.__init__(self, parent, -1, style = style)
+        PanelBase.__init__(self, parent)
+        self.frame = parent
+        self.Bind(EVT_PLOT_RESULT, self.on_plot_results)
+        self.frame.Bind(wx.EVT_CLOSE, self.on_close)
+        self._manager = None
+
+    def on_close(self, event):
+        if event.CanVeto():
+            self.frame.Hide()
+            event.Veto()
+        else:
+            event.Skip()
+
+    def on_plot_results(self, event):
+        self.frame.Show()
+        result = event.result[0][0]
+        if hasattr(result, 'convergence'):
+            from bumps.gui.convergence_view import ConvergenceView
+            best, pop = result.convergence[:,0], result.convergence[:,1:]
+            self.get_panel(ConvergenceView).update(best, pop)
+        if hasattr(result, 'uncertainty_state'):
+            from bumps.gui.uncertainty_view import UncertaintyView, CorrelationView, TraceView
+            from bumps.dream.stats import format_vars
+            self.get_panel(CorrelationView).update(result.uncertainty_state)
+            self.get_panel(UncertaintyView).update(result.uncertainty_state)
+            self.get_panel(TraceView).update(result.uncertainty_state)
+            # TODO: stats should be stored in result rather than computed in bumps UncertaintyView
+            msg = format_vars(self.get_panel(UncertaintyView).stats)
+            wx.PostEvent(self.frame.parent,
+                         StatusEvent(status=msg, info="info"))
+            print
+
+    def get_frame(self):
+        return self.frame
+
+    def add_panel(self, panel):
+        self.AddPage(panel, panel.title)
+
+    def get_panel(self, panel_class):
+        for idx in range(self.PageCount):
+            if self.GetPageText(idx) == panel_class.title:
+                return self.GetPage(idx)
+        else:
+            panel = panel_class(self)
+            self.add_panel(panel)
+            return panel
