Index: DataLoader/data_info.py
===================================================================
--- DataLoader/data_info.py	(revision 273318881b9e2a755400d594daa9bded4396e5dd)
+++ DataLoader/data_info.py	(revision 3cd95c80822fdcf11e0c1dee71e67952ab058df1)
@@ -77,5 +77,11 @@
     ymax = None
     data = None
-    err_data = None
+    qx_data     = None
+    qy_data     = None
+    q_data      = None
+    err_data    = None
+    dqx_data    = None
+    dqy_data    = None
+    mask        = None
     
     # Units
@@ -87,8 +93,14 @@
     _zunit = ''
     
-    def __init__(self, data=None, err_data=None):
+    def __init__(self, data=None, err_data=None, qx_data=None, qy_data=None, q_data=None,mask=None, dqx_data=None, dqy_data=None):
         self.data = numpy.asarray(data)
+        self.qx_data = numpy.asarray(qx_data)
+        self.qy_data = numpy.asarray(qy_data)
+        self.q_data = numpy.asarray(q_data)
+        self.mask = numpy.asarray(mask)
         self.err_data = numpy.asarray(err_data)
-        
+        if dqx_data is not None: self.dqx_data = numpy.asarray(dqx_data) 
+        if dqy_data is not None: self.dqy_data = numpy.asarray(dqy_data) 
+               
     def xaxis(self, label, unit):
         self._xaxis = label
@@ -688,9 +700,9 @@
     
     
-    def __init__(self, data=None, err_data=None):
+    def __init__(self, data=None, err_data=None, qx_data=None, qy_data=None, q_data=None, mask=None, dqx_data=None, dqy_data=None):
         self.y_bins = []
         self.x_bins = []
         DataInfo.__init__(self)
-        plottable_2D.__init__(self, data, err_data)
+        plottable_2D.__init__(self, data, err_data, qx_data, qy_data, q_data,mask, dqx_data, dqy_data)
         if len(self.detector)>0:
             raise RuntimeError, "Data2D: Detector bank already filled at init"
@@ -705,6 +717,6 @@
         leny = 0
         if len(self.data)>0:
-            leny = len(self.data[0])
-        _str += "   Length:       %g x %g\n" % (len(self.data), leny)
+            leny = len(self.data)
+        _str += "   Length:       %g \n" % (len(self.data))
         
         return _str
@@ -724,6 +736,12 @@
             data     = numpy.zeros(length) 
             err_data = numpy.zeros(length) 
-            clone = Data2D(data, err_data)
-            
+            qx_data = numpy.zeros(length)
+            qy_data = numpy.zeros(length)
+            q_data = numpy.zeros(length)
+            mask = numpy.zeros(length)
+            dqx_data = None
+            dqy_data = None
+            clone = Data2D(data, err_data, qx_data, qy_data, q_data,mask, dqx_data=dqx_data, dqy_data=dqy_data)
+
         clone.title       = self.title
         clone.run         = self.run
Index: DataLoader/readers/red2d_reader.py
===================================================================
--- DataLoader/readers/red2d_reader.py	(revision 3cd95c80822fdcf11e0c1dee71e67952ab058df1)
+++ DataLoader/readers/red2d_reader.py	(revision 3cd95c80822fdcf11e0c1dee71e67952ab058df1)
@@ -0,0 +1,312 @@
+"""
+    TXT/IGOR 2D Q Map file reader
+"""
+
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation. 
+
+If you use DANSE applications to do scientific research that leads to 
+publication, we ask that you acknowledge the use of the software with the 
+following sentence:
+
+"This work benefited from DANSE software developed under NSF award DMR-0520547." 
+
+copyright 2008, University of Tennessee
+"""
+
+import os, sys
+import numpy
+import math, logging
+from DataLoader.data_info import Data2D, Detector
+
+# Look for unit converter
+has_converter = True
+try:
+    from data_util.nxsunit import Converter
+except:
+    has_converter = False
+
+class Reader:
+    """ Simple data reader for Igor data files """
+    ## File type
+    type_name = "IGOR/DAT 2D Q_map"   
+    ## Wildcards
+    type = ["IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"]
+    ## Extension
+    ext=['.DAT', '.dat']
+
+    def read(self,filename=None):
+        """ Read file """
+        if not os.path.isfile(filename):
+            raise ValueError, \
+            "Specified file %s is not a regular file" % filename
+        
+        # Read file
+        f = open(filename,'r')
+        buf = f.read()
+        
+        # Instantiate data object
+        output = Data2D()
+        output.filename = os.path.basename(filename)
+        detector = Detector()
+        if len(output.detector)>0: print str(output.detector[0])
+        output.detector.append(detector)
+                
+        # Get content
+        dataStarted = False
+        
+        ## Defaults      
+        lines = buf.split('\n')
+        itot = 0
+        x = []
+        y = []
+        
+        ncounts = 0
+        
+        wavelength   = None
+        distance     = None
+        transmission = None
+        
+        pixel_x = None
+        pixel_y = None
+        
+        i_x    = 0
+        i_y    = -1
+        pixels = 0
+        
+        isInfo   = False
+        isCenter = False
+
+        data_conv_q = None
+        data_conv_i = None
+        
+        # Set units: This is the unit assumed for Q and I in the data file.
+        if has_converter == True and output.Q_unit != '1/A':
+            data_conv_q = Converter('1/A')
+            # Test it
+            data_conv_q(1.0, output.Q_unit)
+            
+        if has_converter == True and output.I_unit != '1/cm':
+            data_conv_i = Converter('1/cm')
+            # Test it
+            data_conv_i(1.0, output.I_unit)            
+        
+        #Set the space for data
+        data = numpy.zeros(0)
+        qx_data = numpy.zeros(0)
+        qy_data = numpy.zeros(0)
+        q_data = numpy.zeros(0)
+        dqx_data = numpy.zeros(0)
+        dqy_data = numpy.zeros(0)
+        mask = numpy.zeros(0,dtype=bool)
+        
+        #Read Header and 2D data
+        for line in lines:      
+            ## Reading the header applies only to IGOR/NIST 2D q_map data files
+            # Find setup info line
+            if isInfo:
+                isInfo = False
+                line_toks = line.split()
+                # Wavelength in Angstrom
+                try:
+                    wavelength = float(line_toks[1])
+                    # Units
+                    if has_converter==True and output.source.wavelength_unit != 'A':
+                        conv = Converter('A')
+                        wavelength = conv(wavelength, units=output.source.wavelength_unit)
+                except:
+                    #Not required
+                    pass
+                # Distance in mm
+                try:
+                    distance = float(line_toks[3])
+                    # Units
+                    if has_converter==True and detector.distance_unit != 'm':
+                        conv = Converter('m')
+                        distance = conv(distance, units=detector.distance_unit)
+                except:
+                    #Not required
+                    pass
+                
+                # Distance in meters
+                try:
+                    transmission = float(line_toks[4])
+                except:
+                    #Not required
+                    pass
+                                            
+            if line.count("LAMBDA")>0:
+                isInfo = True
+                
+            # Find center info line
+            if isCenter:
+                isCenter = False                
+                line_toks = line.split()
+                # Center in bin number
+                center_x = float(line_toks[0])
+                center_y = float(line_toks[1])
+
+            if line.count("BCENT")>0:
+                isCenter = True
+                       
+            # Find data start
+            if line.count("Data columns") or line.count("ASCII data")>0:
+                dataStarted = True
+                continue
+
+            ## Read and get data.   
+            if dataStarted == True:
+                line_toks = line.split()               
+                if len(line_toks) == 0:
+                    #empty line
+                    continue
+                elif len(line_toks) < 2: 
+                    #Q-map 2d require 3 or more columns of data          
+                    raise ValueError,"Igor_Qmap_Reader: Can't read this file: Not a proper file format"
+
+                # defaults 
+                dqx_value  = None
+                dqy_value  = None
+                qz_value   = None
+                mask_value = 0
+                
+                ##Read and get data values
+                qx_value =  float(line_toks[0])
+                qy_value =  float(line_toks[1])
+                value    =  float(line_toks[2])
+                
+                try:
+                    #Read qz_value if exist on 4th column
+                    qz_value = float(line_toks[3])                    
+                except:
+                    # Found a non-float entry, skip it: Not required.
+                    pass                            
+                try:
+                    #Read qz_value if exist on 5th column
+                    dqx_value = float(line_toks[4])
+                except:
+                    # Found a non-float entry, skip it: Not required.
+                    pass
+                try:
+                    #Read qz_value if exist on 6th column
+                    dqy_value = float(line_toks[5])
+                except:
+                    # Found a non-float entry, skip it: Not required.
+                    pass                
+                try:
+                    #Read beam block mask if exist on 7th column
+                    mask_value = float(line_toks[6])
+                except:
+                    # Found a non-float entry, skip it
+                    pass 
+                                             
+                # get data  
+                data    = numpy.append(data, value)
+                qx_data = numpy.append(qx_data, qx_value)
+                qy_data = numpy.append(qy_data, qy_value)
+                
+                # optional data
+                if dqx_value != None and numpy.isfinite(dqx_value):               
+                    dqx_data = numpy.append(dqx_data, dqx_value)
+                if dqy_value != None and numpy.isfinite(dqy_value): 
+                    dqy_data = numpy.append(dqy_data, dqy_value) 
+                    
+                # default data
+                if qz_value == None or not numpy.isfinite(qz_value): 
+                    qz_value = 0  
+                if not numpy.isfinite(mask_value)or mask_value ==0 : 
+                    mask_value = 1             
+                q_data  = numpy.append(q_data,numpy.sqrt(qx_value**2+qy_value**2+qz_value**2))
+                # Note: For convenience, mask = False stands for masked while mask = True for unmasked
+                mask    = numpy.append(mask,(mask_value>=1))
+                
+        # Store limits of the image in q space
+        xmin    = numpy.min(qx_data)
+        xmax    = numpy.max(qx_data)
+        ymin    = numpy.min(qy_data)
+        ymax    = numpy.max(qy_data)
+
+        # units
+        if has_converter == True and output.Q_unit != '1/A':
+            xmin = data_conv_q(xmin, units=output.Q_unit)
+            xmax = data_conv_q(xmax, units=output.Q_unit)
+            ymin = data_conv_q(ymin, units=output.Q_unit)
+            ymax = data_conv_q(ymax, units=output.Q_unit)
+            
+        ## calculate the range of the qx and qy_data
+        x_size = math.fabs(xmax - xmin)
+        y_size = math.fabs(ymax - ymin)
+        
+        # calculate the number of pixels in the each axes
+        npix_y = math.floor(math.sqrt(len(data)))
+        npix_x = math.floor(len(data)/npix_y)
+        
+        # calculate the size of bins      
+        xstep = x_size/(npix_x-1)
+        ystep = y_size/(npix_y-1)
+        
+        # store x and y axis bin centers in q space
+        x_bins  = numpy.arange(xmin,xmax+xstep,xstep)
+        y_bins  = numpy.arange(ymin,ymax+ystep,ystep)
+       
+        # get the limits of q values
+        xmin = xmin - xstep/2
+        xmax = xmax + xstep/2
+        ymin = ymin - ystep/2
+        ymax = ymax + ystep/2
+        
+        #Store data in outputs  
+        #TODO: Check the lengths 
+        output.data     = data
+        output.err_data = numpy.sqrt(numpy.abs(data))
+        output.qx_data  = qx_data
+        output.qy_data  = qy_data             
+        output.q_data   = q_data
+        output.mask     = mask 
+        
+        output.x_bins = x_bins
+        output.y_bins = y_bins
+               
+        output.xmin = xmin
+        output.xmax = xmax
+        output.ymin = ymin
+        output.ymax = ymax
+        
+        output.source.wavelength = wavelength
+        
+        # Store pixel size in mm
+        detector.pixel_size.x = pixel_x
+        detector.pixel_size.y = pixel_y
+        
+        # Store the sample to detector distance
+        detector.distance = distance
+        
+        # optional data: if any of dq data == 0, do not pass to output
+        if len(dqx_data) == len(qx_data):
+            output.dqx_data = dqx_data
+        if len(dqy_data) == len(qy_data):
+            output.dqy_data = dqy_data
+        
+        # Units of axes
+        if data_conv_q is not None:
+            output.xaxis("\\rm{Q_{x}}", output.Q_unit)
+            output.yaxis("\\rm{Q_{y}}", output.Q_unit)
+        else:
+            output.xaxis("\\rm{Q_{x}}", 'A^{-1}')
+            output.yaxis("\\rm{Q_{y}}", 'A^{-1}')            
+        if data_conv_i is not None:
+            output.zaxis("\\rm{Intensity}", output.I_unit)
+        else:
+            output.zaxis("\\rm{Intensity}","cm^{-1}")
+    
+        # Store loading process information
+        output.meta_data['loader'] = self.type_name
+
+        return output
+    
+if __name__ == "__main__": 
+    reader = Reader()
+    print reader.read("../test/exp18_14_igor_2dqxqy.dat") 
+        
