Index: src/sas/qtgui/DataExplorer.py
===================================================================
--- src/sas/qtgui/DataExplorer.py	(revision 49e124c52be5a9defa0e30c2f2e91a421488aff1)
+++ src/sas/qtgui/DataExplorer.py	(revision 14d9c7bfd748108864629dda5188d8f1b6bea4c0)
@@ -388,6 +388,4 @@
         """
         Create a new matplotlib chart from selected data
-
-        TODO: Add 2D-functionality
         """
         plots = GuiUtils.plotsFromCheckedItems(self.model)
@@ -437,8 +435,9 @@
         old_plot = PlotHelper.plotById(plot_id)
 
-        # Add new data to the old plot
+        # Add new data to the old plot, if data type is the same.
         for plot_set in new_plots:
-            old_plot.data(plot_set)
-            old_plot.plot()
+            if type(plot_set) is type(old_plot._data):
+                old_plot.data(plot_set)
+                old_plot.plot()
 
     def chooseFiles(self):
Index: src/sas/qtgui/PlotUtilities.py
===================================================================
--- src/sas/qtgui/PlotUtilities.py	(revision 14d9c7bfd748108864629dda5188d8f1b6bea4c0)
+++ src/sas/qtgui/PlotUtilities.py	(revision 14d9c7bfd748108864629dda5188d8f1b6bea4c0)
@@ -0,0 +1,176 @@
+import sys
+import numpy
+
+
+def build_matrix(data, qx_data, qy_data):
+    """
+    Build a matrix for 2d plot from a vector
+    Returns a matrix (image) with ~ square binning
+    Requirement: need 1d array formats of
+    data, qx_data, and qy_data
+    where each one corresponds to z, x, or y axis values
+
+    """
+    # No qx or qy given in a vector format
+    if qx_data == None or qy_data == None \
+            or qx_data.ndim != 1 or qy_data.ndim != 1:
+        return data
+
+    # maximum # of loops to fillup_pixels
+    # otherwise, loop could never stop depending on data
+    max_loop = 1
+    # get the x and y_bin arrays.
+    x_bins, y_bins = get_bins(qx_data, qy_data)
+    # set zero to None
+
+    #Note: Can not use scipy.interpolate.Rbf:
+    # 'cause too many data points (>10000)<=JHC.
+    # 1d array to use for weighting the data point averaging
+    #when they fall into a same bin.
+    weights_data = numpy.ones([data.size])
+    # get histogram of ones w/len(data); this will provide
+    #the weights of data on each bins
+    weights, xedges, yedges = numpy.histogram2d(x=qy_data,
+                                                y=qx_data,
+                                                bins=[y_bins, x_bins],
+                                                weights=weights_data)
+    # get histogram of data, all points into a bin in a way of summing
+    image, xedges, yedges = numpy.histogram2d(x=qy_data,
+                                                y=qx_data,
+                                                bins=[y_bins, x_bins],
+                                                weights=data)
+    # Now, normalize the image by weights only for weights>1:
+    # If weight == 1, there is only one data point in the bin so
+    # that no normalization is required.
+    image[weights > 1] = image[weights > 1] / weights[weights > 1]
+    # Set image bins w/o a data point (weight==0) as None (was set to zero
+    # by histogram2d.)
+    image[weights == 0] = None
+
+    # Fill empty bins with 8 nearest neighbors only when at least
+    #one None point exists
+    loop = 0
+
+    # do while loop until all vacant bins are filled up up
+    #to loop = max_loop
+    while not(numpy.isfinite(image[weights == 0])).all():
+        if loop >= max_loop:  # this protects never-ending loop
+            break
+        image = fillup_pixels(image=image, weights=weights)
+        loop += 1
+
+    return image
+
+def get_bins(qx_data, qy_data):
+    """
+    get bins
+    return x_bins and y_bins: 1d arrays of the index with
+    ~ square binning
+    Requirement: need 1d array formats of
+    qx_data, and qy_data
+    where each one corresponds to  x, or y axis values
+    """
+    # No qx or qy given in a vector format
+    if qx_data == None or qy_data == None \
+            or qx_data.ndim != 1 or qy_data.ndim != 1:
+        return data
+
+    # find max and min values of qx and qy
+    xmax = qx_data.max()
+    xmin = qx_data.min()
+    ymax = qy_data.max()
+    ymin = qy_data.min()
+
+    # calculate the range of qx and qy: this way, it is a little
+    # more independent
+    x_size = xmax - xmin
+    y_size = ymax - ymin
+
+    # estimate the # of pixels on each axes
+    npix_y = int(numpy.floor(numpy.sqrt(len(qy_data))))
+    npix_x = int(numpy.floor(len(qy_data) / npix_y))
+
+    # bin size: x- & y-directions
+    xstep = x_size / (npix_x - 1)
+    ystep = y_size / (npix_y - 1)
+
+    # max and min taking account of the bin sizes
+    xmax = xmax + xstep / 2.0
+    xmin = xmin - xstep / 2.0
+    ymax = ymax + ystep / 2.0
+    ymin = ymin - ystep / 2.0
+
+    # store x and y bin centers in q space
+    x_bins = numpy.linspace(xmin, xmax, npix_x)
+    y_bins = numpy.linspace(ymin, ymax, npix_y)
+
+    #set x_bins and y_bins
+    return x_bins, y_bins
+
+def fillup_pixels(image=None, weights=None):
+    """
+    Fill z values of the empty cells of 2d image matrix
+    with the average over up-to next nearest neighbor points
+
+    :param image: (2d matrix with some zi = None)
+
+    :return: image (2d array )
+
+    :TODO: Find better way to do for-loop below
+
+    """
+    # No image matrix given
+    if image == None or numpy.ndim(image) != 2 \
+            or numpy.isfinite(image).all() \
+            or weights == None:
+        return image
+    # Get bin size in y and x directions
+    len_y = len(image)
+    len_x = len(image[1])
+    temp_image = numpy.zeros([len_y, len_x])
+    weit = numpy.zeros([len_y, len_x])
+    # do for-loop for all pixels
+    for n_y in range(len(image)):
+        for n_x in range(len(image[1])):
+            # find only null pixels
+            if weights[n_y][n_x] > 0 or numpy.isfinite(image[n_y][n_x]):
+                continue
+            else:
+                # find 4 nearest neighbors
+                # check where or not it is at the corner
+                if n_y != 0 and numpy.isfinite(image[n_y - 1][n_x]):
+                    temp_image[n_y][n_x] += image[n_y - 1][n_x]
+                    weit[n_y][n_x] += 1
+                if n_x != 0 and numpy.isfinite(image[n_y][n_x - 1]):
+                    temp_image[n_y][n_x] += image[n_y][n_x - 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y - 1 and numpy.isfinite(image[n_y + 1][n_x]):
+                    temp_image[n_y][n_x] += image[n_y + 1][n_x]
+                    weit[n_y][n_x] += 1
+                if n_x != len_x - 1 and numpy.isfinite(image[n_y][n_x + 1]):
+                    temp_image[n_y][n_x] += image[n_y][n_x + 1]
+                    weit[n_y][n_x] += 1
+                # go 4 next nearest neighbors when no non-zero
+                # neighbor exists
+                if n_y != 0 and n_x != 0 and\
+                        numpy.isfinite(image[n_y - 1][n_x - 1]):
+                    temp_image[n_y][n_x] += image[n_y - 1][n_x - 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y - 1 and n_x != 0 and \
+                    numpy.isfinite(image[n_y + 1][n_x - 1]):
+                    temp_image[n_y][n_x] += image[n_y + 1][n_x - 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y and n_x != len_x - 1 and \
+                    numpy.isfinite(image[n_y - 1][n_x + 1]):
+                    temp_image[n_y][n_x] += image[n_y - 1][n_x + 1]
+                    weit[n_y][n_x] += 1
+                if n_y != len_y - 1 and n_x != len_x - 1 and \
+                    numpy.isfinite(image[n_y + 1][n_x + 1]):
+                    temp_image[n_y][n_x] += image[n_y + 1][n_x + 1]
+                    weit[n_y][n_x] += 1
+
+    # get it normalized
+    ind = (weit > 0)
+    image[ind] = temp_image[ind] / weit[ind]
+
+    return image
Index: src/sas/qtgui/Plotter2D.py
===================================================================
--- src/sas/qtgui/Plotter2D.py	(revision 49e124c52be5a9defa0e30c2f2e91a421488aff1)
+++ src/sas/qtgui/Plotter2D.py	(revision 14d9c7bfd748108864629dda5188d8f1b6bea4c0)
@@ -16,4 +16,5 @@
 DEFAULT_CMAP = pylab.cm.jet
 
+import PlotUtilities
 import PlotHelper
 
@@ -60,5 +61,5 @@
     def data(self, data=None):
         """ data setter """
-        self._data = data.data
+        self._data = data
         self._qx_data=data.qx_data
         self._qy_data=data.qy_data
@@ -116,5 +117,5 @@
         # self.figure.subplots_adjust(left=0.2, right=.8, bottom=.2)
 
-        output = self._build_matrix()
+        output = PlotUtilities.build_matrix(self._data.data, self._qx_data, self._qy_data)
 
         im = ax.imshow(output,
@@ -144,176 +145,2 @@
         event.accept()
 
-    def _build_matrix(self):
-        """
-        Build a matrix for 2d plot from a vector
-        Returns a matrix (image) with ~ square binning
-        Requirement: need 1d array formats of
-        self.data, self._qx_data, and self._qy_data
-        where each one corresponds to z, x, or y axis values
-
-        """
-        # No qx or qy given in a vector format
-        if self._qx_data == None or self._qy_data == None \
-                or self._qx_data.ndim != 1 or self._qy_data.ndim != 1:
-            # do we need deepcopy here?
-            return self._data
-
-        # maximum # of loops to fillup_pixels
-        # otherwise, loop could never stop depending on data
-        max_loop = 1
-        # get the x and y_bin arrays.
-        self._get_bins()
-        # set zero to None
-
-        #Note: Can not use scipy.interpolate.Rbf:
-        # 'cause too many data points (>10000)<=JHC.
-        # 1d array to use for weighting the data point averaging
-        #when they fall into a same bin.
-        weights_data = numpy.ones([self._data.size])
-        # get histogram of ones w/len(data); this will provide
-        #the weights of data on each bins
-        weights, xedges, yedges = numpy.histogram2d(x=self._qy_data,
-                                                    y=self._qx_data,
-                                                    bins=[self.y_bins, self.x_bins],
-                                                    weights=weights_data)
-        # get histogram of data, all points into a bin in a way of summing
-        image, xedges, yedges = numpy.histogram2d(x=self._qy_data,
-                                                  y=self._qx_data,
-                                                  bins=[self.y_bins, self.x_bins],
-                                                  weights=self._data)
-        # Now, normalize the image by weights only for weights>1:
-        # If weight == 1, there is only one data point in the bin so
-        # that no normalization is required.
-        image[weights > 1] = image[weights > 1] / weights[weights > 1]
-        # Set image bins w/o a data point (weight==0) as None (was set to zero
-        # by histogram2d.)
-        image[weights == 0] = None
-
-        # Fill empty bins with 8 nearest neighbors only when at least
-        #one None point exists
-        loop = 0
-
-        # do while loop until all vacant bins are filled up up
-        #to loop = max_loop
-        while not(numpy.isfinite(image[weights == 0])).all():
-            if loop >= max_loop:  # this protects never-ending loop
-                break
-            image = self._fillup_pixels(image=image, weights=weights)
-            loop += 1
-
-        return image
-
-    def _get_bins(self):
-        """
-        get bins
-        set x_bins and y_bins into self, 1d arrays of the index with
-        ~ square binning
-        Requirement: need 1d array formats of
-        self._qx_data, and self._qy_data
-        where each one corresponds to  x, or y axis values
-        """
-        # No qx or qy given in a vector format
-        if self._qx_data == None or self._qy_data == None \
-                or self._qx_data.ndim != 1 or self._qy_data.ndim != 1:
-            return self._data
-
-        # find max and min values of qx and qy
-        xmax = self._qx_data.max()
-        xmin = self._qx_data.min()
-        ymax = self._qy_data.max()
-        ymin = self._qy_data.min()
-
-        # calculate the range of qx and qy: this way, it is a little
-        # more independent
-        x_size = xmax - xmin
-        y_size = ymax - ymin
-
-        # estimate the # of pixels on each axes
-        npix_y = int(numpy.floor(numpy.sqrt(len(self._qy_data))))
-        npix_x = int(numpy.floor(len(self._qy_data) / npix_y))
-
-        # bin size: x- & y-directions
-        xstep = x_size / (npix_x - 1)
-        ystep = y_size / (npix_y - 1)
-
-        # max and min taking account of the bin sizes
-        xmax = xmax + xstep / 2.0
-        xmin = xmin - xstep / 2.0
-        ymax = ymax + ystep / 2.0
-        ymin = ymin - ystep / 2.0
-
-        # store x and y bin centers in q space
-        x_bins = numpy.linspace(xmin, xmax, npix_x)
-        y_bins = numpy.linspace(ymin, ymax, npix_y)
-
-        #set x_bins and y_bins
-        self.x_bins = x_bins
-        self.y_bins = y_bins
-
-    def _fillup_pixels(self, image=None, weights=None):
-        """
-        Fill z values of the empty cells of 2d image matrix
-        with the average over up-to next nearest neighbor points
-
-        :param image: (2d matrix with some zi = None)
-
-        :return: image (2d array )
-
-        :TODO: Find better way to do for-loop below
-
-        """
-        # No image matrix given
-        if image == None or numpy.ndim(image) != 2 \
-                or numpy.isfinite(image).all() \
-                or weights == None:
-            return image
-        # Get bin size in y and x directions
-        len_y = len(image)
-        len_x = len(image[1])
-        temp_image = numpy.zeros([len_y, len_x])
-        weit = numpy.zeros([len_y, len_x])
-        # do for-loop for all pixels
-        for n_y in range(len(image)):
-            for n_x in range(len(image[1])):
-                # find only null pixels
-                if weights[n_y][n_x] > 0 or numpy.isfinite(image[n_y][n_x]):
-                    continue
-                else:
-                    # find 4 nearest neighbors
-                    # check where or not it is at the corner
-                    if n_y != 0 and numpy.isfinite(image[n_y - 1][n_x]):
-                        temp_image[n_y][n_x] += image[n_y - 1][n_x]
-                        weit[n_y][n_x] += 1
-                    if n_x != 0 and numpy.isfinite(image[n_y][n_x - 1]):
-                        temp_image[n_y][n_x] += image[n_y][n_x - 1]
-                        weit[n_y][n_x] += 1
-                    if n_y != len_y - 1 and numpy.isfinite(image[n_y + 1][n_x]):
-                        temp_image[n_y][n_x] += image[n_y + 1][n_x]
-                        weit[n_y][n_x] += 1
-                    if n_x != len_x - 1 and numpy.isfinite(image[n_y][n_x + 1]):
-                        temp_image[n_y][n_x] += image[n_y][n_x + 1]
-                        weit[n_y][n_x] += 1
-                    # go 4 next nearest neighbors when no non-zero
-                    # neighbor exists
-                    if n_y != 0 and n_x != 0 and\
-                         numpy.isfinite(image[n_y - 1][n_x - 1]):
-                        temp_image[n_y][n_x] += image[n_y - 1][n_x - 1]
-                        weit[n_y][n_x] += 1
-                    if n_y != len_y - 1 and n_x != 0 and \
-                        numpy.isfinite(image[n_y + 1][n_x - 1]):
-                        temp_image[n_y][n_x] += image[n_y + 1][n_x - 1]
-                        weit[n_y][n_x] += 1
-                    if n_y != len_y and n_x != len_x - 1 and \
-                        numpy.isfinite(image[n_y - 1][n_x + 1]):
-                        temp_image[n_y][n_x] += image[n_y - 1][n_x + 1]
-                        weit[n_y][n_x] += 1
-                    if n_y != len_y - 1 and n_x != len_x - 1 and \
-                        numpy.isfinite(image[n_y + 1][n_x + 1]):
-                        temp_image[n_y][n_x] += image[n_y + 1][n_x + 1]
-                        weit[n_y][n_x] += 1
-
-        # get it normalized
-        ind = (weit > 0)
-        image[ind] = temp_image[ind] / weit[ind]
-
-        return image
