[GRASS-SVN] r57454 - sandbox/turek/scatter_plot

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Aug 15 12:16:05 PDT 2013


Author: turek
Date: 2013-08-15 12:16:04 -0700 (Thu, 15 Aug 2013)
New Revision: 57454

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
backend clean up and added comments

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-08-13 21:48:39 UTC (rev 57453)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-08-15 19:16:04 UTC (rev 57454)
@@ -1,6 +1,6 @@
 Index: include/defs/vedit.h
 ===================================================================
---- include/defs/vedit.h	(revision 57437)
+--- include/defs/vedit.h	(revision 57453)
 +++ include/defs/vedit.h	(working copy)
 @@ -33,6 +33,8 @@
  int Vedit_merge_lines(struct Map_info *, struct ilist *);
@@ -13,36 +13,37 @@
  
 Index: include/defs/imagery.h
 ===================================================================
---- include/defs/imagery.h	(revision 57437)
+--- include/defs/imagery.h	(revision 57453)
 +++ include/defs/imagery.h	(working copy)
-@@ -110,6 +110,22 @@
+@@ -110,6 +110,23 @@
  FILE *I_fopen_subgroup_ref_new(const char *, const char *);
  FILE *I_fopen_subgroup_ref_old(const char *, const char *);
  
 +/* scatt_plt.c */
 +void I_sc_init_cats(struct scCats *, int, int);
 +void I_sc_free_cats(struct scCats *);
-+int I_sc_add_cat(struct scCats *, int);
++int I_sc_add_cat(struct scCats *);
 +int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
 +
-+void I_scd_init_scatt_data(struct scdScattData *, int, int, void *, struct Range, struct Range);
-+void I_scd_free_scatt_data(struct scdScattData *);
++void I_scd_init_scatt_data(struct scdScattData *, int, int, void *);
 +
 +int I_compute_scatts(struct Cell_head *, struct scCats *, const char **, 
-+                     int, const char **, struct scCats *, const char **);
++	                 const char **, int, struct scCats *, const char **);
 +
 +int I_create_cat_rast(struct Cell_head *, const char *);
 +int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
 +
++int I_id_scatt_to_bands(const int, const int, int *, int *);
++int I_bands_to_id_scatt(const int, const int, const int, int *);
 +
  /* sig.c */
  int I_init_signatures(struct Signature *, int);
  int I_new_signature(struct Signature *);
 Index: include/imagery.h
 ===================================================================
---- include/imagery.h	(revision 57437)
+--- include/imagery.h	(revision 57453)
 +++ include/imagery.h	(working copy)
-@@ -135,6 +135,59 @@
+@@ -135,6 +135,55 @@
      
  } IClass_statistics;
  
@@ -57,16 +58,16 @@
 +*/
 +struct scCats 
 +{
-+    int type;  /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots*/
++    int type;        /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots to be computed*/
 +
-+    int n_cats; /*!< number of alocated categories */
++    int n_cats;      /*!< number of alocated categories */
 +    
-+    int n_bands; /*!< number of analyzed bands */
-+    int n_scatts; /*!< number of possible scattter plot which can be created from bands */
++    int n_bands;     /*!< number of analyzed bands */
++    int n_scatts;    /*!< number of possible scattter plot which can be created from bands */
 +
-+    int   n_a_cats; /*!< number of used categories */
-+    int * cats_ids; /*!< category id */
-+    int * cats_idxs; /*!< internal category idx (idx in cats_arr)*/
++    int   n_a_cats;  /*!< number of used/active categories */
++    int * cats_ids;  /*!< (cat_idx->cat_id) array index is internal idx (position in cats_arr) and id is saved in it's position*/
++    int * cats_idxs; /*!< (cat_id->cat_idx) array index is id and internal idx is saved in it's position*/
 +
 +    struct scScatts ** cats_arr; /*!< array of pointers to struct scScatts */
 +};
@@ -76,11 +77,11 @@
 +*/
 +struct scScatts
 +{
-+    int n_a_scatts; /*!< number of used scatter plots */
++    int n_a_scatts;     /*!< number of used/active scatter plots*/
 +    
 +    int * scatts_bands; /*!< array of bands for which represents the scatter plots, 
-+                             size of  scatts_bands is two times bigger than size of scatts_arr (every scatter plot has assigned two bands)*/
-+    int * scatt_idxs; /*!< internal idx of the scatter plot (idx in scatts_arr)*/
++                             every scatter plot has assigned two bads (size of array is n_a_scatts * 2)*/
++    int * scatt_idxs;   /*!< (scatt_id->scatt_idx) internal idx of the scatter plot (position in scatts_arr)*/
 +
 +    struct scdScattData ** scatts_arr; /*!< array of pointers to scdScattData */
 +};
@@ -90,1310 +91,19 @@
 +struct scdScattData
 +{
 +    int n_vals; /* Number of values in scatter plot. */
-+    
-+    struct Range band_1_range; /* Range of band 1 (min and max), TODO range attributes could be moved to scCats */
-+    struct Range band_2_range; /* Range of band 2 (min and max) */
 +
-+
-+    unsigned char  * b_conds_arr; /* array of selected areas (used for SC_SCATT_CONDITIONS type) */
-+    unsigned int  * scatt_vals_arr; /* array of computed areas (used for SC_SCATT_DATA type) */
++    unsigned char  * b_conds_arr; /* array of selected areas (used for SC_SCATT_CONDITIONS type) otherwise NULL */
++    unsigned int  * scatt_vals_arr; /* array of computed areas (used for SC_SCATT_DATA type) otherwise NULL */
 +};
 +
  #define SIGNATURE_TYPE_MIXED 1
  
  #define GROUPFILE "CURGROUP"
-Index: gui/wxpython/iclass/dialogs.py
-===================================================================
---- gui/wxpython/iclass/dialogs.py	(revision 57437)
-+++ gui/wxpython/iclass/dialogs.py	(working copy)
-@@ -333,13 +333,19 @@
-         toolbar.SetCategories(catNames = catNames, catIdx = cats)
-         if name in catNames:
-             toolbar.choice.SetStringSelection(name)
-+            cat = toolbar.GetSelectedCategoryIdx()
-         elif catNames:
-             toolbar.choice.SetSelection(0)
--            
-+            cat = toolbar.GetSelectedCategoryIdx()
-+        else:
-+            cat = None
-+
-         if toolbar.choice.IsEmpty():
-             toolbar.EnableControls(False)
-         else:
-             toolbar.EnableControls(True)
-+
-+        self.mapWindow.CategoryChanged(cat)
-         # don't forget to update maps, histo, ...
-         
-     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-Index: gui/wxpython/iclass/toolbars.py
-===================================================================
---- gui/wxpython/iclass/toolbars.py	(revision 57437)
-+++ gui/wxpython/iclass/toolbars.py	(working copy)
-@@ -46,9 +46,7 @@
-         'importAreas' : MetaIcon(img = 'layer-import',
-                             label = _('Import training areas from vector map')),
-         'addRgb' : MetaIcon(img = 'layer-rgb-add',
--                            label = _('Add RGB map layer')),
--        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
--                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
-+                            label = _('Add RGB map layer'))
-         }
-         
- class IClassMapToolbar(BaseToolbar):
-@@ -117,10 +115,7 @@
-                                      ("zoomBack", icons["zoomBack"],
-                                       self.parent.OnZoomBack),
-                                      ("zoomToMap", icons["zoomExtent"],
--                                      self.parent.OnZoomToMap),
--                                     (None, ),
--                                     ("scatt_plot", iClassIcons["scatt_plot"],
--                                      self.parent.OnScatterplot)
-+                                      self.parent.OnZoomToMap)
-                                     ))
- class IClassToolbar(BaseToolbar):
-     """!IClass toolbar
-@@ -156,7 +151,7 @@
-         """!Toolbar data"""
-         icons = iClassIcons
-         return self._getToolbarData((("selectGroup", icons['selectGroup'],
--                                      self.parent.OnAddBands),
-+                                      lambda event : self.parent.AddBands()),
-                                       (None, ),
-                                       ("classManager", icons['classManager'],
-                                       self.parent.OnCategoryManager),
-Index: gui/wxpython/iclass/frame.py
-===================================================================
---- gui/wxpython/iclass/frame.py	(revision 57437)
-+++ gui/wxpython/iclass/frame.py	(working copy)
-@@ -65,6 +65,8 @@
-                                IClassExportAreasDialog, IClassMapDialog
- from iclass.plots       import PlotPanel
- 
-+from grass.pydispatch.signal import Signal
-+
- class IClassMapFrame(DoubleMapFrame):
-     """! wxIClass main frame
-     
-@@ -115,6 +117,10 @@
-             lambda:
-             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
-         self.SetSize(size)
-+
-+        self.groupSet = Signal("IClassMapFrame.groupSet")
-+        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
-+
-         #
-         # Add toolbars
-         #
-@@ -178,7 +184,7 @@
-         self.dialogs['category']   = None
-         
-         # PyPlot init
--        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
-+        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
-                                    
-         self._addPanes()
-         self._mgr.Update()
-@@ -231,7 +237,30 @@
-             return False
-         
-         return vectorName
--        
-+    
-+    def OnScatterplot(self, event):
-+        """!Init interactive scatterplot tools
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
-+
-+        try:
-+          from scatt_plot.dialogs import ScattPlotMainDialog
-+          self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
-+
-+          scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
-+          scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().digit)
-+
-+          self.dialogs['scatt_plot'].CenterOnScreen()
-+          self.dialogs['scatt_plot'].Show()
-+
-+        except ImportError as e:
-+          GError(parent  = self, showTraceback = False, message = _("The Scatter Plot Tool is not installed:\n%s" % str(e)))
-+        except Exception as e:
-+          GError(parent  = self, message = _("Unable to launch the Scatter Plot Tool:\n%s" % str(e)))
-+          return
-+
-     def RemoveTempVector(self):
-         """!Removes temporary vector map with training areas"""
-         ret = RunCommand(prog = 'g.remove',
-@@ -471,7 +500,7 @@
-         
-         self.Render(self.GetFirstWindow())
-         
--    def OnAddBands(self, event):
-+    def AddBands(self):
-         """!Add imagery group"""
-         dlg = IClassGroupDialog(self, group = self.group)
-         if dlg.ShowModal() == wx.ID_OK:
-@@ -482,7 +511,8 @@
-         """!Set imagery group"""
-         group = grass.find_file(name = name, element = 'group')
-         if group['name']:
--            self.group = group['name']
-+           self.group = group['name']
-+           self.groupSet.emit(group = group['name'])
-         else:
-             GError(_("Group <%s> not found") % name, parent = self)
-     
-@@ -783,17 +813,20 @@
-         
-         Updates number of stddev, histograms, layer in preview display. 
-         """
--        stat = self.stats_data.GetStatistics(currentCat)
--        nstd = stat.nstd
--        self.toolbars['iClass'].UpdateStddev(nstd)
--        
--        self.plotPanel.UpdateCategory(currentCat)
--        self.plotPanel.OnPlotTypeSelected(None)
-+        if currentCat:
-+          stat = self.stats_data.GetStatistics(currentCat)
-+          nstd = stat.nstd
-+          self.toolbars['iClass'].UpdateStddev(nstd)
-+          
-+          self.plotPanel.UpdateCategory(currentCat)
-+          self.plotPanel.OnPlotTypeSelected(None)
-                                    
--        name = stat.rasterName
--        name = self.previewMapManager.GetAlias(name)
--        if name:
--            self.previewMapManager.SelectLayer(name)
-+          name = stat.rasterName
-+          name = self.previewMapManager.GetAlias(name)
-+          if name:
-+              self.previewMapManager.SelectLayer(name)
-+
-+        self.categoryChanged.emit(cat = currentCat)
-         
-     def DeleteAreas(self, cats):
-         """!Removes all training areas of given categories
-@@ -1120,27 +1153,6 @@
- 
-         self.GetFirstWindow().mouse['use'] = 'pointer'
- 
--    def OnScatterplot(self, event):
--        """!Init interactive scatterplot tools
--        """
--        if self.dialogs['scatt_plot']:
--            self.dialogs['scatt_plot'].Raise()
--            return
--
--        try:
--          from scatt_plot.dialogs import ScattPlotMainDialog
--        except:
--          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
--          return
--
--        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
--
--        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
--        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().digit)
--
--        self.dialogs['scatt_plot'].CenterOnScreen()
--        self.dialogs['scatt_plot'].Show()
--
- class MapManager:
-     """! Class for managing map renderer.
-     
-Index: gui/wxpython/iclass/plots.py
-===================================================================
---- gui/wxpython/iclass/plots.py	(revision 57437)
-+++ gui/wxpython/iclass/plots.py	(working copy)
-@@ -28,7 +28,7 @@
-     for each band and for one category. Coincidence plots show min max range
-     of classes for each band.
-     """
--    def __init__(self, parent, stats_data):
-+    def __init__(self, parent, giface, stats_data):
-         scrolled.ScrolledPanel.__init__(self, parent)
-         
-         self.SetupScrolling(scroll_x = False, scroll_y = True)
-@@ -38,26 +38,62 @@
-         self.stats_data = stats_data
-         self.currentCat = None
-         
-+        self._giface = giface
-+
-         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
--        
-+
-         self._createControlPanel()
--        
-+        self._createPlotPanel()
-+        self._createScatterPlotPanel()
-+
-         self.SetSizer(self.mainSizer)
-         self.mainSizer.Fit(self)
-         self.Layout()
-         
-+    def _createPlotPanel(self):
-+
-+        self.canvasPanel = wx.Panel(parent=self)
-+        self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
-+        self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
-+        self.canvasPanel.SetSizer(self.canvasSizer)
-+
-     def _createControlPanel(self):
-         self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
-                                      choices = [_("Histograms"),
--                                                _("Coincident plots")])
-+                                                _("Coincident plots"),
-+                                                _("Scatter plots")])
-         self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
-         self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
--        
-+    
-+    def _createScatterPlotPanel(self):
-+        """!Init interactive scatterplot tools
-+        """
-+        try:
-+            from scatt_plot.dialogs_iclass import IClassScatterPlotsPanel
-+            self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, giface=self._giface, iclass_mapwin = self.parent.GetFirstWindow())
-+            self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
-+            self.scatt_plot_panel.Hide()
-+        except ImportError as e:
-+            self.scatt_plot_panel = None
-+
-     def OnPlotTypeSelected(self, event):
-         """!Plot type selected"""
-+
-+        if self.plotSwitch.GetSelection() in [0, 1]:
-+            self.SetupScrolling(scroll_x = False, scroll_y = True)
-+            self.scatt_plot_panel.Hide()
-+            self.canvasPanel.Show()
-+            self.Layout()
-+
-+        elif self.plotSwitch.GetSelection() == 2:
-+            self.SetupScrolling(scroll_x = False, scroll_y = False)
-+            self.scatt_plot_panel.Show()
-+            self.canvasPanel.Hide()
-+            self.Layout()
-+
-         if self.currentCat is None:
-             return
--        
-+
-         if self.plotSwitch.GetSelection() == 0:
-             stat = self.stats_data.GetStatistics(self.currentCat)
-             if not stat.IsReady():
-@@ -66,7 +102,10 @@
-             self.DrawHistograms(stat)
-         else:
-             self.DrawCoincidencePlots()
--            
-+
-+        self.Layout()
-+
-+
-     def StddevChanged(self):
-         """!Standard deviation multiplier changed, redraw histograms"""
-         if self.plotSwitch.GetSelection() == 0:
-@@ -89,7 +128,7 @@
-             panel.Destroy()
-             
-         self.canvasList = []
--            
-+
-     def ClearPlots(self):
-         """!Clears plot canvases"""
-         for bandIdx in range(len(self.bandList)):
-@@ -104,15 +143,15 @@
-     def CreatePlotCanvases(self):
-         """!Create plot canvases according to the number of bands"""
-         for band in self.bandList:
--            canvas = plot.PlotCanvas(self)
-+            canvas = plot.PlotCanvas(self.canvasPanel)
-             canvas.SetMinSize((-1, 140))
-             canvas.SetFontSizeTitle(10)
-             canvas.SetFontSizeAxis(8)
-             self.canvasList.append(canvas)
-             
--            self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
--
--        self.SetVirtualSize(self.GetBestVirtualSize()) 
-+            self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
-+        
-+        self.SetVirtualSize(self.GetBestVirtualSize())
-         self.Layout()
-         
-     def UpdatePlots(self, group, currentCat, stats_data):
-@@ -138,7 +177,7 @@
-         
-     def UpdateCategory(self, cat):
-         self.currentCat = cat
--        
-+    
-     def DrawCoincidencePlots(self):
-         """!Draw coincidence plots"""
-         for bandIdx in range(len(self.bandList)):
-Index: gui/wxpython/scatt_plot/gthreading.py
-===================================================================
---- gui/wxpython/scatt_plot/gthreading.py	(revision 0)
-+++ gui/wxpython/scatt_plot/gthreading.py	(working copy)
-@@ -0,0 +1,134 @@
-+"""!
-+ at package scatt_plot.gthreading
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+import os
-+import sys
-+import time
-+import threading
-+import Queue
-+
-+import wx
-+from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
-+
-+class gThread(threading.Thread):
-+    """!Thread for GRASS commands"""
-+    requestId = 0
-+
-+    def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
-+        """!
-+        @param receiver event receiver (used in PostEvent)
-+        """
-+        threading.Thread.__init__(self, **kwds)
-+
-+        if requestQ is None:
-+            self.requestQ = Queue.Queue()
-+        else:
-+            self.requestQ = requestQ
-+
-+        if resultQ is None:
-+            self.resultQ = Queue.Queue()
-+        else:
-+            self.resultQ = resultQ
-+
-+        self.setDaemon(True)
-+
-+        self.receiver = receiver
-+        self._want_abort_all = False
-+
-+        self.start()
-+
-+    def Run(self, *args, **kwds):
-+        """!Run command in queue
-+
-+        @param args unnamed command arguments
-+        @param kwds named command arguments
-+
-+        @return request id in queue
-+        """
-+        gThread.requestId += 1
-+        self.requestQ.put((gThread.requestId, args, kwds))
-+
-+        return gThread.requestId
-+
-+    def GetId(self):
-+         """!Get id for next command"""
-+         return gThread.requestId + 1
-+
-+    def SetId(self, id):
-+        """!Set starting id"""
-+        gThread.requestId = id
-+
-+    def run(self):
-+        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
-+        while True:
-+            requestId, args, kwds = self.requestQ.get()
-+            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
-+                if key in kwds:
-+                    vars()[key] = kwds[key]
-+                    del kwds[key]
-+                else:
-+                    vars()[key] = None
-+
-+            requestTime = time.time()
-+
-+            #if self._want_abort_all and self.requestCmd is not None:
-+            #    self.requestCmd.abort()
-+            #    if self.requestQ.empty():
-+            #        self._want_abort_all = False
-+
-+            # prepare
-+            if self.receiver:
-+                event = wxCmdPrepare(type = 'method',
-+                                     time=requestTime,
-+                                     pid=requestId)
-+
-+                wx.PostEvent(self.receiver, event)
-+
-+                # run command
-+                event = wxCmdRun(type = 'method',
-+                                 pid=requestId)
-+
-+                wx.PostEvent(self.receiver, event)
-+
-+            time.sleep(.1)
-+
-+            ret = None
-+            exception = None
-+            
-+            #to
-+            #try:
-+            ret = vars()['callable'](*args, **kwds)
-+            #except Exception as e:
-+            #    exception  = e;
-+
-+            self.resultQ.put((requestId, ret))
-+
-+            time.sleep(.1)
-+
-+            if self.receiver:
-+                event = wxCmdDone(type = 'cmd',
-+                                  kwds = kwds,
-+                                  args = args, #TODO expand args to kwds
-+                                  ret=ret,
-+                                  exception=exception,
-+                                  pid=requestId)
-+
-+                # send event
-+                wx.PostEvent(self.receiver, event)
-+
-+    def abort(self, abortall=True):
-+        """!Abort command(s)"""
-+        if abortall:
-+            self._want_abort_all = True
-+        if self.requestQ.empty():
-+            self._want_abort_all = False
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/dialogs_iclass.py
-===================================================================
---- gui/wxpython/scatt_plot/dialogs_iclass.py	(revision 0)
-+++ gui/wxpython/scatt_plot/dialogs_iclass.py	(working copy)
-@@ -0,0 +1,436 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+import wx.lib.scrolledpanel as scrolled
-+import wx.lib.mixins.listctrl as listmix
-+import wx.lib.flatnotebook  as FN
-+import wx.aui
-+
-+from core import globalvar
-+from core.gcmd import GException, GError, RunCommand
-+
-+from gui_core.gselect import Select
-+
-+from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars_iclass import MainToolbar
-+from scatt_plot.sc_pl_core import idScattToidBands
-+from scatt_plot.plots import ScatterPlotWidget
-+
-+try:
-+    from agw import aui
-+except ImportError:
-+    import wx.lib.agw.aui as aui
-+
-+class IClassScatterPlotsPanel(wx.Panel):
-+    def __init__(self, parent, giface, iclass_mapwin = None,
-+                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+
-+        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
-+        #                           style = wx.SP_LIVE_UPDATE)
-+        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
-+
-+        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
-+        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
-+
-+        # toobars
-+        self.toolbars = {}
-+        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
-+        self._createCategoryPanel(self)
-+
-+        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
-+
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
-+        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
-+        self.catsPanel.Hide()
-+        self.SetSizer(mainsizer)
-+
-+        
-+        #self.SetSashGravity(0.5)
-+        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
-+        self.Layout()
-+        #self.SetAutoLayout(1)
-+
-+    def NewScatterPlot(self, scatt_id):
-+        return self.plot_panel.NewScatterPlot(scatt_id)
-+
-+    def ShowCategoryPanel(self, show):
-+        self.catsPanel.Show(show)
-+        
-+        #if show:
-+        #    self.SetSashSize(5) 
-+        #else:
-+        #    self.SetSashSize(0)
-+        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
-+        self.Layout()
-+
-+    def _createCategoryPanel(self, parent):
-+        self.catsPanel = wx.Panel(parent = parent)
-+        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
-+                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
-+
-+        self.catsPanel.SetMaxSize((-1, 150))
-+
-+        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
-+                             label = ' %s ' % _("Classes manager for scatter plots"))
-+        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
-+
-+        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
-+        self.catsPanel.SetSizer(catsSizer)
-+
-+
-+class IClassPlotPanel(scrolled.ScrolledPanel):
-+    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
-+    
-+        scrolled.ScrolledPanel.__init__(self, parent)
-+        self.SetupScrolling(scroll_x = False, scroll_y = True)
-+
-+        self.scatt_mgr = scatt_mgr
-+
-+        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
-+
-+        #self._createCategoryPanel()
-+        # Fancy gui
-+        self._mgr = aui.AuiManager(self.mainPanel)
-+        #self._mgr.SetManagedWindow(self)
-+
-+        self._mgr.Update()
-+
-+        self._doLayout()
-+        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
-+
-+        dlgSize = (-1, 400)
-+        #self.SetBestSize(dlgSize)
-+        #self.SetInitialSize(dlgSize)
-+        self.SetAutoLayout(1)
-+        #fix goutput's pane size (required for Mac OSX)
-+        #if self.gwindow:         
-+        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
-+    
-+    def OnScroll(self, event):
-+        event.Skip()
-+        wx.CallAfter(self._mgr.Update)
-+        wx.CallAfter(self.Layout)
-+
-+    def _doLayout(self):
-+
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
-+        self.SetSizer(mainsizer)
-+
-+        self.Layout()
-+        self.SetupScrolling()
-+
-+    def OnCloseDialog(self, event):
-+        """!Close dialog"""
-+        self.scatt_mgr.CleanUp()
-+        self.Destroy()
-+
-+    def OnSettings(self, event):
-+        pass
-+
-+    def NewScatterPlot(self, scatt_id):
-+        #TODO needs to be resolved (should be in this class)
-+
-+        scatt = ScatterPlotWidget(parent = self.mainPanel, 
-+                                  scatt_mgr = self.scatt_mgr, 
-+                                  scatt_id = scatt_id)
-+
-+        bands = self.scatt_mgr.GetBands()
-+        #TODO too low level
-+        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
-+
-+        self._mgr.AddPane(scatt,
-+                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
-+                           Name("scatter plot %d" % scatt_id).MinSize((-1, 300)).Caption(("%s x: %s y: %s") % (_("scatter plot"), bands[b1_id], bands[b2_id])).
-+                           Center().Position(1).MaximizeButton(True).
-+                           MinimizeButton(True).CaptionVisible(True).
-+                           CloseButton(True).Layer(0))
-+        self._mgr.Update()
-+  
-+        self.SetVirtualSize(self.GetBestVirtualSize())
-+        self.Layout()
-+
-+        return scatt
-+
-+    def GetScattMgr(self):
-+        return  self.scatt_mgr
-+
-+class CategoryListCtrl(wx.ListCtrl,
-+                       listmix.ListCtrlAutoWidthMixin,
-+                       listmix.TextEditMixin):
-+
-+    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
-+
-+        wx.ListCtrl.__init__(self, parent, id,
-+                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
-+        self.columns = ((_('Class name'), 'name'),
-+                        (_('Color'), 'color'))
-+        self.Populate(columns = self.columns)
-+        
-+        self.cats_mgr = cats_mgr
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+        self.rightClickedItemIdx = wx.NOT_FOUND
-+        
-+        listmix.ListCtrlAutoWidthMixin.__init__(self)
-+
-+        listmix.TextEditMixin.__init__(self)
-+        
-+        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
-+        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
-+             
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+        self.cats_mgr.deletedCategory.connect(self.Update)
-+        self.cats_mgr.addedCategory.connect(self.Update)
-+
-+    def Update(self, **kwargs):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+    def InitCoreCats(self):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+    def SetVirtualData(self, row, column, text):
-+        attr = self.columns[column][1]
-+        if attr == 'name':
-+            try:
-+                text.encode('ascii')
-+            except UnicodeEncodeError:
-+                GMessage(parent = self, message = _("Please use only ASCII characters."))
-+                return
-+
-+        cat_id = self.cats_mgr.GetCategories()[row]
-+
-+        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
-+        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+        
-+        self.Select(row)
-+        
-+    def Populate(self, columns):
-+        for i, col in enumerate(columns):
-+            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
-+
-+        self.SetColumnWidth(0, 100)
-+        self.SetColumnWidth(1, 100)
-+        
-+    def AddCategory(self):
-+
-+        self.cats_mgr.addedCategory.disconnect(self.Update)
-+        cat_id = self.cats_mgr.AddCategory()
-+        self.cats_mgr.addedCategory.connect(self.Update)
-+
-+        if cat_id < 0:
-+            GError(_("Maximum limit of categories number was reached."))
-+            return
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+                        
-+    def DeleteCategory(self):
-+        indexList = sorted(self.GetSelectedIndices(), reverse = True)
-+        cats = []
-+        for i in indexList:
-+            # remove temporary raster
-+            cat_id = self.cats_mgr.GetCategories()[i]
-+            
-+            cats.append(cat_id)
-+
-+            self.cats_mgr.deletedCategory.disconnect(self.Update)
-+            self.cats_mgr.DeleteCategory(cat_id)
-+            self.cats_mgr.deletedCategory.connect(self.Update)
-+            
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        
-+    def OnSel(self, event): 
-+        event.Skip()
-+
-+    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-+        indices = []
-+        lastFound = -1
-+        while True:
-+            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
-+            if index == -1:
-+                break
-+            else:
-+                lastFound = index
-+                indices.append(index)
-+        return indices        
-+
-+    def OnEdit(self, event):
-+        currentItem = event.m_itemIndex
-+        currentCol = event.m_col
-+
-+        if currentCol == 1:
-+            dlg = wx.ColourDialog(self)
-+            dlg.GetColourData().SetChooseFull(True)
-+
-+            if dlg.ShowModal() == wx.ID_OK:
-+                color = dlg.GetColourData().GetColour().Get()
-+                color = ':'.join(map(str, color))
-+                self.SetVirtualData(currentItem, currentCol, color)
-+            dlg.Destroy()
-+            wx.CallAfter(self.SetFocus)
-+        
-+        event.Skip()
-+        
-+        
-+    def DeselectAll(self):
-+        """!Deselect all items"""
-+        indexList = self.GetSelectedIndices()
-+        for i in indexList:
-+            self.Select(i, on = 0)
-+         
-+        # no highlight
-+        self.OnCategorySelected(None)
-+        
-+    def OnGetItemText(self, item, col):
-+        attr = self.columns[col][1]
-+        cat_id = self.cats_mgr.GetCategories()[item]
-+
-+        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
-+
-+    def OnGetItemImage(self, item):
-+        return -1
-+
-+    def OnGetItemAttr(self, item):
-+        return None
-+        
-+class AddScattPlotDialog(wx.Dialog):
-+
-+    def __init__(self, parent, bands, id  = wx.ID_ANY):
-+        
-+        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+        self.bands = bands
-+
-+        self.scatt_id = None
-+
-+        self._createWidgets()
-+
-+    def _createWidgets(self):
-+
-+        self.labels = {}
-+        self.params = {}
-+
-+        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        # buttons
-+        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+        
-+        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+        self._layout()
-+
-+    def _layout(self):
-+
-+        border = wx.BoxSizer(wx.VERTICAL) 
-+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
-+                                                    sel = self.band_1_ch))
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
-+                                                    sel = self.band_2_ch))
-+
-+        # buttons
-+        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+        self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+        
-+        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+
-+        dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+                        flag = wx.ALIGN_CENTER)
-+
-+        border.Add(item = dialogSizer, proportion = 0,
-+                   flag = wx.ALL, border = 5)
-+
-+        self.SetSizer(border)
-+        self.Layout()
-+        self.Fit()
-+
-+        # bindings
-+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+    def _addSelectSizer(self, title, sel): 
-+        """!Helper layout function.
-+        """
-+        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+        selTitleSizer.Add(item = title, proportion = 1,
-+                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+        selSizer.Add(item = selTitleSizer, proportion = 0,
-+                     flag = wx.EXPAND)
-+
-+        selSizer.Add(item = sel, proportion = 1,
-+                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+                     border = 5)
-+
-+        return selSizer
-+
-+    def OnClose(self, event):
-+        """!Close dialog
-+        """
-+        if not self.IsModal():
-+            self.Destroy()
-+        event.Skip()
-+
-+    def OnOk(self, event):
-+        """!
-+        """
-+        band_1 = self.band_1_ch.GetSelection()
-+        band_2 = self.band_2_ch.GetSelection()
-+
-+
-+        if band_1 == band_2:
-+            GError(_("Selected bands must be different."))
-+            return
-+        
-+        #TODO axes selection
-+        if band_1 > band_2:
-+            tmp_band = band_2
-+            band_2 = band_1
-+            band_1 = band_2
-+
-+        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
-+
-+        event.Skip()
-+
-+    def GetScattId(self):
-+        return self.scatt_id
-Index: gui/wxpython/scatt_plot/dialogs.py
-===================================================================
---- gui/wxpython/scatt_plot/dialogs.py	(revision 0)
-+++ gui/wxpython/scatt_plot/dialogs.py	(working copy)
-@@ -0,0 +1,142 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+from scatt_plot.sc_pl_core import idBandsToidScatt
-+
-+class AddScattPlotDialog(wx.Dialog):
-+
-+    def __init__(self, parent, bands, id  = wx.ID_ANY):
-+        
-+        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+        self.bands = bands
-+
-+        self.scatt_id = None
-+
-+        self._createWidgets()
-+
-+    def _createWidgets(self):
-+
-+        self.labels = {}
-+        self.params = {}
-+
-+        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        # buttons
-+        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+        
-+        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+        self._layout()
-+
-+    def _layout(self):
-+
-+        border = wx.BoxSizer(wx.VERTICAL) 
-+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
-+                                                    sel = self.band_1_ch))
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
-+                                                    sel = self.band_2_ch))
-+
-+        # buttons
-+        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+        self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+        
-+        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+
-+        dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+                        flag = wx.ALIGN_CENTER)
-+
-+        border.Add(item = dialogSizer, proportion = 0,
-+                   flag = wx.ALL, border = 5)
-+
-+        self.SetSizer(border)
-+        self.Layout()
-+        self.Fit()
-+
-+        # bindings
-+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+    def _addSelectSizer(self, title, sel): 
-+        """!Helper layout function.
-+        """
-+        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+        selTitleSizer.Add(item = title, proportion = 1,
-+                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+        selSizer.Add(item = selTitleSizer, proportion = 0,
-+                     flag = wx.EXPAND)
-+
-+        selSizer.Add(item = sel, proportion = 1,
-+                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+                     border = 5)
-+
-+        return selSizer
-+
-+    def OnClose(self, event):
-+        """!Close dialog
-+        """
-+        if not self.IsModal():
-+            self.Destroy()
-+        event.Skip()
-+
-+    def OnOk(self, event):
-+        """!
-+        """
-+        band_1 = self.band_1_ch.GetSelection()
-+        band_2 = self.band_2_ch.GetSelection()
-+
-+
-+        if band_1 == band_2:
-+            GError(_("Selected bands must be different."))
-+            return
-+        
-+        #TODO axes selection
-+        if band_1 > band_2:
-+            tmp_band = band_2
-+            band_2 = band_1
-+            band_1 = band_2
-+
-+        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
-+
-+        event.Skip()
-+
-+    def GetScattId(self):
-+        return self.scatt_id
-Index: gui/wxpython/scatt_plot/toolbars_iclass.py
-===================================================================
---- gui/wxpython/scatt_plot/toolbars_iclass.py	(revision 0)
-+++ gui/wxpython/scatt_plot/toolbars_iclass.py	(working copy)
-@@ -0,0 +1,106 @@
-+"""!
-+ at package scatt_plot.toolbars
-+
-+ at brief Scatter plot - toolbars
-+
-+Classes:
-+ - toolbars::MainToolbar
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+
-+import wx
-+
-+from icons.icon import MetaIcon
-+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd import RunCommand
-+from core.gcmd import GException, GError, RunCommand
-+from scatt_plot.sc_pl_core import idBandsToidScatt
-+
-+
-+class MainToolbar(BaseToolbar):
-+    """!Main toolbar
-+    """
-+    def __init__(self, parent, scatt_mgr):
-+        BaseToolbar.__init__(self, parent)
-+        self.scatt_mgr = scatt_mgr
-+
-+        self.InitToolbar(self._toolbarData())
-+        
-+        # realize the toolbar
-+        self.Realize()
-+
-+    def _toolbarData(self):
-+
-+        icons = {
-+                 'settings'   : BaseIcons['settings'].SetLabel( _('Ssettings')),
-+                 'help'       : MetaIcon(img = 'help',
-+                                         label = _('Show manual')),
-+                 'add_scatt_pl'  : MetaIcon(img = 'layer-raster-analyze',
-+                                            label = _('Add scatter plot')),
-+                 'editCatAdd'  : MetaIcon(img = 'polygon-create',
-+                                          label = _('Add region to category mode')),
-+                 'editCatRemove'  : MetaIcon(img = 'polygon-delete',
-+                                             label = _('Remove region to category mode')),
-+                 'pan'        : MetaIcon(img = 'pan',
-+                                         label = _('Pan'),
-+                                         desc = _('Drag with mouse to pan scatter plots (zoom with holding right mouse button and draging')),
-+                'zoomIn'     : MetaIcon(img = 'zoom-in',
-+                                          label = _('Zoom in'),
-+                                          desc = _('Zoom with rectangle in scatter plots.')),
-+                'cats_mgr' : MetaIcon(img = 'table-manager',
-+                                          label = _('Class manager'))
-+                }
-+
-+        return self._getToolbarData((
-+                                     ("cats_mgr", icons['cats_mgr'],
-+                                     lambda event: self.parent.ShowCategoryPanel(event.Checked()), wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ("pan", icons["pan"],
-+                                     lambda event: self.SetPloltsMode(event, 'pan'),
-+                                      wx.ITEM_CHECK),
-+                                     ("zoom", icons["zoomIn"],
-+                                     lambda event: self.SetPloltsMode(event, 'zoom'),
-+                                      wx.ITEM_CHECK),
-+                                     ('add', icons['editCatAdd'],
-+                                     lambda event: self.SetPloltsMode(event, 'add'),
-+                                     wx.ITEM_CHECK),
-+                                     ('remove', icons['editCatRemove'],
-+                                     lambda event: self.SetPloltsMode(event, 'remove'),
-+                                     wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ('add_scatt', icons["add_scatt_pl"],
-+                                     lambda event : self.scatt_mgr.AddScattPlot())
-+                                     #('settings', icon["settings"],
-+                                     # self.parent.OnSettings),  
-+                                     #('help', icons["help"],
-+                                     # self.OnHelp),                    
-+                                    ))
-+
-+    def GetToolId(self, toolName): #TODO can be useful in base
-+
-+        return vars(self)[toolName]            
-+
-+    def SetPloltsMode(self, event, tool_name):
-+
-+        #TODO move to toolbars
-+        if  event.Checked()  == True:
-+            for i_tool_data in  self._data:
-+                i_tool_name = i_tool_data[0]
-+                if  not i_tool_name or i_tool_name == "cats_mgr":
-+                    continue
-+                if i_tool_name == tool_name:
-+                    continue
-+                i_tool_id = vars(self)[i_tool_name]
-+
-+                self.ToggleTool(i_tool_id, False)
-+            self.scatt_mgr.SetPlotsMode(mode = tool_name)
-+            return
-+
-+        self.scatt_mgr.SetPlotsMode(mode = None)
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/toolbars.py
-===================================================================
---- gui/wxpython/scatt_plot/toolbars.py	(revision 0)
-+++ gui/wxpython/scatt_plot/toolbars.py	(working copy)
-@@ -0,0 +1,106 @@
-+"""!
-+ at package scatt_plot.toolbars
-+
-+ at brief Scatter plot - toolbars
-+
-+Classes:
-+ - toolbars::MainToolbar
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+
-+import wx
-+
-+from icons.icon import MetaIcon
-+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd import RunCommand
-+
-+class MainToolbar(BaseToolbar):
-+    """!Main toolbar
-+    """
-+    def __init__(self, parent):
-+        BaseToolbar.__init__(self, parent)
-+        
-+        self.InitToolbar(self._toolbarData())
-+        
-+        # realize the toolbar
-+        self.Realize()
-+
-+    def _toolbarData(self):
-+
-+        icons = {
-+                 'set_data'    : MetaIcon(img = 'layer-raster-add',
-+                                         label = _('Set input raster data for plots')),
-+                 'settings'   : BaseIcons['settings'].SetLabel( _('Ssettings')),
-+                 'help'       : MetaIcon(img = 'help',
-+                                         label = _('Show manual')),
-+                 'add_scatt_pl'  : MetaIcon(img = 'layer-raster-analyze',
-+                                            label = _('Add scatter plot'))
-+                }
-+
-+        return self._getToolbarData((
-+                                     ('sat_data', icons["set_data"],
-+                                      self.parent.OnSetData),
-+                                     (None, ),
-+                                     ('add_scatt', icons["add_scatt_pl"],
-+                                      self.parent.OnAddScattPl),
-+                                     #('settings', icons["settings"],
-+                                     # self.parent.OnSettings),  
-+                                     #('help', icons["help"],
-+                                     # self.OnHelp),                    
-+                                     ("quit", BaseIcons['quit'],
-+                                      self.parent.OnCloseDialog)
-+                                    ))
-+
-+    def OnHelp(self, event) :
-+            RunCommand('g.manual',
-+                       entry = 'wxGUI.scatt_plot')
-+
-+class CategoriesToolbar(BaseToolbar):
-+
-+    def __init__(self, parent, cats_list, scatts_dlg):
-+        BaseToolbar.__init__(self, parent)
-+        self.cats_list = cats_list
-+        self.scatts_dlg = scatts_dlg
-+
-+        self.InitToolbar(self._toolbarData())
-+        
-+
-+        # realize the toolbar
-+        self.Realize()
-+
-+
-+    def _toolbarData(self):
-+
-+        icons = {
-+            'editCatAdd'  : MetaIcon(img = 'polygon-create',
-+                                     label = _('Add region to category mode')),
-+            'editCatRemove'  : MetaIcon(img = 'polygon-delete',
-+                                        label = _('Remove region to category mode')),
-+            'addCat'     : MetaIcon(img = 'layer-add',
-+                                    label = _('Add category')),
-+            'deleteCat'  : MetaIcon(img = 'layer-remove',
-+                                    label = _('Delete category'))
-+            }
-+
-+        return  self._getToolbarData((('editCatAdd', icons['editCatAdd'],
-+                                        lambda event: self.scatts_dlg.EditCatAdd(),
-+                                        wx.ITEM_CHECK),
-+                                      ('editCatRemove', icons['editCatRemove'],
-+                                        lambda event: self.scatts_dlg.EditCatRemove(),
-+                                        wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ('addCat', icons["addCat"],
-+                                        lambda event: self.cats_list.AddCategory()),
-+                                     ('deleteCat', icons["deleteCat"],
-+                                        lambda event: self.cats_list.DeleteCategory())))
-+                                    
-+    def GetToolId(self, toolName): #TODO can be useful in base
-+
-+        return vars(self)[toolName]            
-\ No newline at end of file
 Index: gui/wxpython/scatt_plot/core_c.py
 ===================================================================
 --- gui/wxpython/scatt_plot/core_c.py	(revision 0)
 +++ gui/wxpython/scatt_plot/core_c.py	(working copy)
-@@ -0,0 +1,226 @@
+@@ -0,0 +1,167 @@
 +"""!
 + at package scatt_plot.scatt_plot
 +
@@ -1409,26 +119,21 @@
 + at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
 +"""
 +
++import sys
 +from multiprocessing import Process, Queue
 +
 +from ctypes import *
 +try:
 +    from grass.lib.imagery import *
 +    from grass.lib.gis import Cell_head, G_get_window
-+    #from grass.lib.raster import struct_Range
-+
-+
 +except ImportError, e:
 +    sys.stderr.write(_("Loading imagery lib failed"))
 +
-+def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
++from core.gcmd import GException
 +
-+    return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, None)
 +
-+    # Queue object for interprocess communication
++def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
 +    q = Queue()
-+
-+    # The separate render process
 +    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
 +                                                    n_bands, scatts, cats_rasts_in, cats_rasts_out, q))
 +    p.start()
@@ -1438,20 +143,13 @@
 +    return ret[0], ret[1]
 +
 +def UpdateCatRast(patch_rast, region, cat_rast):
-+
-+    #return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts, None)
-+    # Queue object for interprocess communication
-+
-+    #_updateCatRastProcess(patch_rast, region, cat_rast, None)
-+    #return 
 +    q = Queue()
-+    # The separate render process
 +    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
 +    p.start()
-+    #ret = q.get()
++    ret = q.get()
 +    p.join()
 +
-+    #return ret[0], ret[1]
++    return ret
 +
 +def CreateCatRast(region, cat_rast):
 +
@@ -1461,8 +159,8 @@
 +def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, output_queue):
 +
 +    #TODO names for types not 0 and 1?
-+    sccats_c, vals_dt = _getComputationStruct(scatts, 0, n_bands)
-+    scatt_conds_c, vals_dt2 = _getComputationStruct(scatt_conds, 1, n_bands)
++    sccats_c, refs = _getComputationStruct(scatts, 0, n_bands)
++    scatt_conds_c, refs2 = _getComputationStruct(scatt_conds, 1, n_bands)
 +
 +    char_bands = _stringListToCharArr(bands)
 +    char_cats_rasts_out = _stringListToCharArr(cats_rasts_out)
@@ -1472,17 +170,16 @@
 +
 +    ret = I_compute_scatts(pointer(cell_head),
 +                           pointer(scatt_conds_c),
++                           pointer(char_cats_rasts_in),
 +                           pointer(char_bands),
 +                           n_bands,
-+                           pointer(char_cats_rasts_in),
 +                           pointer(sccats_c),
 +                           pointer(char_cats_rasts_out))
 +
 +    I_sc_free_cats(pointer(sccats_c))
 +    I_sc_free_cats(pointer(scatt_conds_c))
 +
-+    #output_queue.put((ret, scatts))
-+    return (ret, scatts)
++    output_queue.put((ret, scatts))
 +
 +def _getBandcRange( band_info):
 +    band_c_range = struct_Range()
@@ -1532,22 +229,15 @@
 +    sccats = struct_scCats()
 +    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
 +        
-+    #for i in range(sccats.n_a_cats):
-+    #    cat_id = sccats.cats_ids[i]
-+    #    I_sc_delete_cat(pointer(sccats), cat_id)
-+    #    i -= 1
-+
-+    vals_dt = []
++    refs = []
 +    for cat_id, scatt_ids in cats.iteritems():
-+        I_sc_add_cat(pointer(sccats), cat_id)
++        cat_c_id = I_sc_add_cat(pointer(sccats))
 +
 +        for scatt_id, dt in scatt_ids.iteritems():
 +            # if key is missing condition is always True (full scatter plor is computed)
 +            if cats[cat_id].has_key(scatt_id):
 +
 +                vals = dt['np_vals']
-+                b1_info = dt['bands_info']['b1']
-+                b2_info = dt['bands_info']['b2']
 +
 +                scatt_vals = scdScattData()
 +
@@ -1559,67 +249,28 @@
 +                    pass
 +                else:
 +                    return None
-+
-+                b1_c_info = _getBandcRange(b1_info)
-+                b2_c_info =_getBandcRange(b2_info)
 +                data_p = vals.ctypes.data_as(c_void_p)
-+                I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p, 
-+                                      b1_c_info, b2_c_info)
++                I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p)
 +
-+                vals_dt.append(scatt_vals)
++                refs.append(scatt_vals)
 +
 +                I_sc_insert_scatt_data(pointer(sccats),  
 +                                       pointer(scatt_vals),
-+                                       cat_id, scatt_id)
++                                       cat_c_id, scatt_id)
 +
-+    return sccats, vals_dt
++    return sccats, refs
 +
 +def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
-+
-+    #TODO names for types not 0 and 1?
-+
 +    cell_head = _regionToCellHead(region)
 +    
 +    
-+    I_insert_patch_to_cat_rast(patch_rast, 
-+                               pointer(cell_head), 
-+                               cat_rast)
++    ret = I_insert_patch_to_cat_rast(patch_rast, 
++                                     pointer(cell_head), 
++                                     cat_rast)
 +
-+    #print re
-+    #output_queue.put((ret, scatts))
-+     #return (ret, scatts)
++    output_queue.put(ret)
 +
-+"""
-+class A:
-+    def __init__(self):        
-+        self.i = 0        
 +
-+    def incr(self):
-+        self.i += 1
-+        return self.i
-+
-+def worker(input, output):
-+    print "ahoj"
-+    for func, args in iter(input.get, 'STOP'):
-+        print "jedu"
-+        result = func.incr
-+        output.put(result)
-+
-+def test():
-+    # Create queues
-+    task_queue = Queue()
-+    done_queue = Queue()
-+
-+    # Start worker processes
-+    a = A()
-+
-+    prc = Process(target=worker, args=(task_queue, done_queue)).start()
-+    task_queue.put((a,1))
-+
-+    data = done_queue.get()
-+    print data
-+    task_queue.put('STOP')
-+"""
 Index: gui/wxpython/scatt_plot/__init__.py
 ===================================================================
 --- gui/wxpython/scatt_plot/__init__.py	(revision 0)
@@ -2436,7 +1087,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/sc_pl_core.py	(revision 0)
 +++ gui/wxpython/scatt_plot/sc_pl_core.py	(working copy)
-@@ -0,0 +1,619 @@
+@@ -0,0 +1,627 @@
 +"""!
 + at package scatt_plot.scatt_plot
 +
@@ -2563,6 +1214,8 @@
 +        returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
 +                                           len(self.GetBands()), scatts, cats_rasts_conds, cats_rasts)
 +        
++        if returncode < 0:
++            GException(_("Computing of scatter plots failed."))
 +        #self.scatts_dt.SetData(scatts)
 +
 +    def CatRastUpdater(self):
@@ -2625,10 +1278,11 @@
 +            self._rasterize(grass_region, layer, cat, patch_rast)
 +
 +            region = self.an_data.GetRegion()
-+            UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
-+            
++            ret = UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
++            if ret < 0:
++                GException(_("Patching category raster conditions file failed."))            
 +            RunCommand("g.remove",
-+                       rast = patch_rast)#,
++                      rast = patch_rast)
 +
 +    def _rasterize(self, grass_region, layer, cat, out_rast):
 +
@@ -2636,7 +1290,9 @@
 +        ret, text, msg = RunCommand("v.build",
 +                                      map = self.vectMap,
 +                                      getErrorMsg = True,
-+                                      read = True)#,
++                                      read = True)
++        if ret != 0:
++            GException(_("v.build failed:\n%s" % msg))
 +
 +        #TODO thread problem with env variable remove it!!!!
 +        environs = os.environ.copy()
@@ -2652,6 +1308,10 @@
 +                                    read = True,
 +                                    overwrite = True,
 +                                    env = environs)
++
++        if ret != 0:
++            GException(_("v.to.rast failed:\n%s" % msg))
++
 +    def _create_grass_region_env(self, bbox):
 +
 +        region = self.an_data.GetRegion()
@@ -2944,10 +1604,9 @@
 +        else:
 +            self.cats_rasts_conds[cat_id] = grass.tempfile()
 +            self.cats_rasts[cat_id] = "temp_cat_rast_%d" % cat_id
++            region = self.an_data.GetRegion()
++            CreateCatRast(region, self.cats_rasts_conds[cat_id])
 +
-+        region = self.an_data.GetRegion()
-+        CreateCatRast(region, self.cats_rasts_conds[cat_id])   
-+
 +        return cat_id
 +
 +    def DeleteCategory(self, cat_id):
@@ -3056,60 +1715,1007 @@
 +
 +    return scatt_id
 +
-Index: gui/wxpython/Makefile
+Index: gui/wxpython/scatt_plot/gthreading.py
 ===================================================================
---- gui/wxpython/Makefile	(revision 57437)
-+++ gui/wxpython/Makefile	(working copy)
-@@ -13,7 +13,7 @@
- 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
- 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
- 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* vdigit/* \
--	vnet/*.py web_services/*.py wxplot/*.py) \
-+	vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
- 	gis_set.py gis_set_error.py wxgui.py README
- 
- DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
-@@ -21,7 +21,7 @@
- 
- PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
- 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
--	mapswipe vdigit wxplot web_services rlisetup vnet)
-+	mapswipe vdigit wxplot web_services rlisetup vnet scatt_plot)
- 
- DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
- 
-Index: gui/wxpython/vdigit/toolbars.py
+--- gui/wxpython/scatt_plot/gthreading.py	(revision 0)
++++ gui/wxpython/scatt_plot/gthreading.py	(working copy)
+@@ -0,0 +1,134 @@
++"""!
++ at package scatt_plot.gthreading
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++import os
++import sys
++import time
++import threading
++import Queue
++
++import wx
++from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
++
++class gThread(threading.Thread):
++    """!Thread for GRASS commands"""
++    requestId = 0
++
++    def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
++        """!
++        @param receiver event receiver (used in PostEvent)
++        """
++        threading.Thread.__init__(self, **kwds)
++
++        if requestQ is None:
++            self.requestQ = Queue.Queue()
++        else:
++            self.requestQ = requestQ
++
++        if resultQ is None:
++            self.resultQ = Queue.Queue()
++        else:
++            self.resultQ = resultQ
++
++        self.setDaemon(True)
++
++        self.receiver = receiver
++        self._want_abort_all = False
++
++        self.start()
++
++    def Run(self, *args, **kwds):
++        """!Run command in queue
++
++        @param args unnamed command arguments
++        @param kwds named command arguments
++
++        @return request id in queue
++        """
++        gThread.requestId += 1
++        self.requestQ.put((gThread.requestId, args, kwds))
++
++        return gThread.requestId
++
++    def GetId(self):
++         """!Get id for next command"""
++         return gThread.requestId + 1
++
++    def SetId(self, id):
++        """!Set starting id"""
++        gThread.requestId = id
++
++    def run(self):
++        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
++        while True:
++            requestId, args, kwds = self.requestQ.get()
++            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
++                if key in kwds:
++                    vars()[key] = kwds[key]
++                    del kwds[key]
++                else:
++                    vars()[key] = None
++
++            requestTime = time.time()
++
++            #if self._want_abort_all and self.requestCmd is not None:
++            #    self.requestCmd.abort()
++            #    if self.requestQ.empty():
++            #        self._want_abort_all = False
++
++            # prepare
++            if self.receiver:
++                event = wxCmdPrepare(type = 'method',
++                                     time=requestTime,
++                                     pid=requestId)
++
++                wx.PostEvent(self.receiver, event)
++
++                # run command
++                event = wxCmdRun(type = 'method',
++                                 pid=requestId)
++
++                wx.PostEvent(self.receiver, event)
++
++            time.sleep(.1)
++
++            ret = None
++            exception = None
++            
++            #to
++            #try:
++            ret = vars()['callable'](*args, **kwds)
++            #except Exception as e:
++            #    exception  = e;
++
++            self.resultQ.put((requestId, ret))
++
++            time.sleep(.1)
++
++            if self.receiver:
++                event = wxCmdDone(type = 'cmd',
++                                  kwds = kwds,
++                                  args = args, #TODO expand args to kwds
++                                  ret=ret,
++                                  exception=exception,
++                                  pid=requestId)
++
++                # send event
++                wx.PostEvent(self.receiver, event)
++
++    def abort(self, abortall=True):
++        """!Abort command(s)"""
++        if abortall:
++            self._want_abort_all = True
++        if self.requestQ.empty():
++            self._want_abort_all = False
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/dialogs_iclass.py
 ===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57437)
-+++ gui/wxpython/vdigit/toolbars.py	(working copy)
-@@ -17,6 +17,7 @@
- import wx
- 
- from grass.script import core as grass
-+from grass.pydispatch.signal import Signal
- 
- from gui_core.toolbars  import BaseToolbar, BaseIcons
- from gui_core.dialogs   import CreateNewVector
-@@ -42,6 +43,8 @@
-         self.digit         = None
-         self._giface       = giface
-         
-+        self.editingStarted = Signal("VDigitToolbar.editingStarted")
+--- gui/wxpython/scatt_plot/dialogs_iclass.py	(revision 0)
++++ gui/wxpython/scatt_plot/dialogs_iclass.py	(working copy)
+@@ -0,0 +1,436 @@
++"""!
++ at package scatt_plot.dialogs
 +
-         # currently selected map layer for editing (reference to MapLayer instance)
-         self.mapLayer = None
-         # list of vector layers from Layer Manager (only in the current mapset)
-@@ -818,6 +821,7 @@
-             alpha = int(opacity * 255)
-             self.digit.GetDisplay().UpdateSettings(alpha = alpha)
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++import wx.lib.scrolledpanel as scrolled
++import wx.lib.mixins.listctrl as listmix
++import wx.lib.flatnotebook  as FN
++import wx.aui
++
++from core import globalvar
++from core.gcmd import GException, GError, RunCommand
++
++from gui_core.gselect import Select
++
++from scatt_plot.controllers import ScattsManager
++from scatt_plot.toolbars_iclass import MainToolbar
++from scatt_plot.sc_pl_core import idScattToidBands
++from scatt_plot.plots import ScatterPlotWidget
++
++try:
++    from agw import aui
++except ImportError:
++    import wx.lib.agw.aui as aui
++
++class IClassScatterPlotsPanel(wx.Panel):
++    def __init__(self, parent, giface, iclass_mapwin = None,
++                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++
++        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
++        #                           style = wx.SP_LIVE_UPDATE)
++        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++
++        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
++        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
++
++        # toobars
++        self.toolbars = {}
++        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        self._createCategoryPanel(self)
++
++        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
++        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
++        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
++        self.catsPanel.Hide()
++        self.SetSizer(mainsizer)
++
++        
++        #self.SetSashGravity(0.5)
++        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
++        self.Layout()
++        #self.SetAutoLayout(1)
++
++    def NewScatterPlot(self, scatt_id):
++        return self.plot_panel.NewScatterPlot(scatt_id)
++
++    def ShowCategoryPanel(self, show):
++        self.catsPanel.Show(show)
++        
++        #if show:
++        #    self.SetSashSize(5) 
++        #else:
++        #    self.SetSashSize(0)
++        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
++        self.Layout()
++
++    def _createCategoryPanel(self, parent):
++        self.catsPanel = wx.Panel(parent = parent)
++        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
++                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
++
++        self.catsPanel.SetMaxSize((-1, 150))
++
++        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
++                             label = ' %s ' % _("Classes manager for scatter plots"))
++        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
++
++        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++        self.catsPanel.SetSizer(catsSizer)
++
++
++class IClassPlotPanel(scrolled.ScrolledPanel):
++    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
++    
++        scrolled.ScrolledPanel.__init__(self, parent)
++        self.SetupScrolling(scroll_x = False, scroll_y = True)
++
++        self.scatt_mgr = scatt_mgr
++
++        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
++
++        #self._createCategoryPanel()
++        # Fancy gui
++        self._mgr = aui.AuiManager(self.mainPanel)
++        #self._mgr.SetManagedWindow(self)
++
++        self._mgr.Update()
++
++        self._doLayout()
++        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
++
++        dlgSize = (-1, 400)
++        #self.SetBestSize(dlgSize)
++        #self.SetInitialSize(dlgSize)
++        self.SetAutoLayout(1)
++        #fix goutput's pane size (required for Mac OSX)
++        #if self.gwindow:         
++        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++    
++    def OnScroll(self, event):
++        event.Skip()
++        wx.CallAfter(self._mgr.Update)
++        wx.CallAfter(self.Layout)
++
++    def _doLayout(self):
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
++        self.SetSizer(mainsizer)
++
++        self.Layout()
++        self.SetupScrolling()
++
++    def OnCloseDialog(self, event):
++        """!Close dialog"""
++        self.scatt_mgr.CleanUp()
++        self.Destroy()
++
++    def OnSettings(self, event):
++        pass
++
++    def NewScatterPlot(self, scatt_id):
++        #TODO needs to be resolved (should be in this class)
++
++        scatt = ScatterPlotWidget(parent = self.mainPanel, 
++                                  scatt_mgr = self.scatt_mgr, 
++                                  scatt_id = scatt_id)
++
++        bands = self.scatt_mgr.GetBands()
++        #TODO too low level
++        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
++
++        self._mgr.AddPane(scatt,
++                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
++                           Name("scatter plot %d" % scatt_id).MinSize((-1, 300)).Caption(("%s x: %s y: %s") % (_("scatter plot"), bands[b1_id], bands[b2_id])).
++                           Center().Position(1).MaximizeButton(True).
++                           MinimizeButton(True).CaptionVisible(True).
++                           CloseButton(True).Layer(0))
++        self._mgr.Update()
++  
++        self.SetVirtualSize(self.GetBestVirtualSize())
++        self.Layout()
++
++        return scatt
++
++    def GetScattMgr(self):
++        return  self.scatt_mgr
++
++class CategoryListCtrl(wx.ListCtrl,
++                       listmix.ListCtrlAutoWidthMixin,
++                       listmix.TextEditMixin):
++
++    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++
++        wx.ListCtrl.__init__(self, parent, id,
++                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++        self.columns = ((_('Class name'), 'name'),
++                        (_('Color'), 'color'))
++        self.Populate(columns = self.columns)
++        
++        self.cats_mgr = cats_mgr
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++        self.rightClickedItemIdx = wx.NOT_FOUND
++        
++        listmix.ListCtrlAutoWidthMixin.__init__(self)
++
++        listmix.TextEditMixin.__init__(self)
++        
++        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
++        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
++             
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++        self.cats_mgr.deletedCategory.connect(self.Update)
++        self.cats_mgr.addedCategory.connect(self.Update)
++
++    def Update(self, **kwargs):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def InitCoreCats(self):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def SetVirtualData(self, row, column, text):
++        attr = self.columns[column][1]
++        if attr == 'name':
++            try:
++                text.encode('ascii')
++            except UnicodeEncodeError:
++                GMessage(parent = self, message = _("Please use only ASCII characters."))
++                return
++
++        cat_id = self.cats_mgr.GetCategories()[row]
++
++        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
++        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++        
++        self.Select(row)
++        
++    def Populate(self, columns):
++        for i, col in enumerate(columns):
++            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++
++        self.SetColumnWidth(0, 100)
++        self.SetColumnWidth(1, 100)
++        
++    def AddCategory(self):
++
++        self.cats_mgr.addedCategory.disconnect(self.Update)
++        cat_id = self.cats_mgr.AddCategory()
++        self.cats_mgr.addedCategory.connect(self.Update)
++
++        if cat_id < 0:
++            GError(_("Maximum limit of categories number was reached."))
++            return
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++                        
++    def DeleteCategory(self):
++        indexList = sorted(self.GetSelectedIndices(), reverse = True)
++        cats = []
++        for i in indexList:
++            # remove temporary raster
++            cat_id = self.cats_mgr.GetCategories()[i]
++            
++            cats.append(cat_id)
++
++            self.cats_mgr.deletedCategory.disconnect(self.Update)
++            self.cats_mgr.DeleteCategory(cat_id)
++            self.cats_mgr.deletedCategory.connect(self.Update)
++            
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        
++    def OnSel(self, event): 
++        event.Skip()
++
++    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
++        indices = []
++        lastFound = -1
++        while True:
++            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
++            if index == -1:
++                break
++            else:
++                lastFound = index
++                indices.append(index)
++        return indices        
++
++    def OnEdit(self, event):
++        currentItem = event.m_itemIndex
++        currentCol = event.m_col
++
++        if currentCol == 1:
++            dlg = wx.ColourDialog(self)
++            dlg.GetColourData().SetChooseFull(True)
++
++            if dlg.ShowModal() == wx.ID_OK:
++                color = dlg.GetColourData().GetColour().Get()
++                color = ':'.join(map(str, color))
++                self.SetVirtualData(currentItem, currentCol, color)
++            dlg.Destroy()
++            wx.CallAfter(self.SetFocus)
++        
++        event.Skip()
++        
++        
++    def DeselectAll(self):
++        """!Deselect all items"""
++        indexList = self.GetSelectedIndices()
++        for i in indexList:
++            self.Select(i, on = 0)
++         
++        # no highlight
++        self.OnCategorySelected(None)
++        
++    def OnGetItemText(self, item, col):
++        attr = self.columns[col][1]
++        cat_id = self.cats_mgr.GetCategories()[item]
++
++        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
++
++    def OnGetItemImage(self, item):
++        return -1
++
++    def OnGetItemAttr(self, item):
++        return None
++        
++class AddScattPlotDialog(wx.Dialog):
++
++    def __init__(self, parent, bands, id  = wx.ID_ANY):
++        
++        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++        self.bands = bands
++
++        self.scatt_id = None
++
++        self._createWidgets()
++
++    def _createWidgets(self):
++
++        self.labels = {}
++        self.params = {}
++
++        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        # buttons
++        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++        
++        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++        self._layout()
++
++    def _layout(self):
++
++        border = wx.BoxSizer(wx.VERTICAL) 
++        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
++                                                    sel = self.band_1_ch))
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
++                                                    sel = self.band_2_ch))
++
++        # buttons
++        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++        self.btnsizer.Add(item = self.btn_close, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++        
++        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++
++        dialogSizer.Add(item = self.btnsizer, proportion = 0,
++                        flag = wx.ALIGN_CENTER)
++
++        border.Add(item = dialogSizer, proportion = 0,
++                   flag = wx.ALL, border = 5)
++
++        self.SetSizer(border)
++        self.Layout()
++        self.Fit()
++
++        # bindings
++        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++    def _addSelectSizer(self, title, sel): 
++        """!Helper layout function.
++        """
++        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++        selTitleSizer.Add(item = title, proportion = 1,
++                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++        selSizer.Add(item = selTitleSizer, proportion = 0,
++                     flag = wx.EXPAND)
++
++        selSizer.Add(item = sel, proportion = 1,
++                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++                     border = 5)
++
++        return selSizer
++
++    def OnClose(self, event):
++        """!Close dialog
++        """
++        if not self.IsModal():
++            self.Destroy()
++        event.Skip()
++
++    def OnOk(self, event):
++        """!
++        """
++        band_1 = self.band_1_ch.GetSelection()
++        band_2 = self.band_2_ch.GetSelection()
++
++
++        if band_1 == band_2:
++            GError(_("Selected bands must be different."))
++            return
++        
++        #TODO axes selection
++        if band_1 > band_2:
++            tmp_band = band_2
++            band_2 = band_1
++            band_1 = band_2
++
++        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++
++        event.Skip()
++
++    def GetScattId(self):
++        return self.scatt_id
+Index: gui/wxpython/scatt_plot/dialogs.py
+===================================================================
+--- gui/wxpython/scatt_plot/dialogs.py	(revision 0)
++++ gui/wxpython/scatt_plot/dialogs.py	(working copy)
+@@ -0,0 +1,142 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++from scatt_plot.sc_pl_core import idBandsToidScatt
++
++class AddScattPlotDialog(wx.Dialog):
++
++    def __init__(self, parent, bands, id  = wx.ID_ANY):
++        
++        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++        self.bands = bands
++
++        self.scatt_id = None
++
++        self._createWidgets()
++
++    def _createWidgets(self):
++
++        self.labels = {}
++        self.params = {}
++
++        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        # buttons
++        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++        
++        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++        self._layout()
++
++    def _layout(self):
++
++        border = wx.BoxSizer(wx.VERTICAL) 
++        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
++                                                    sel = self.band_1_ch))
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
++                                                    sel = self.band_2_ch))
++
++        # buttons
++        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++        self.btnsizer.Add(item = self.btn_close, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++        
++        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++
++        dialogSizer.Add(item = self.btnsizer, proportion = 0,
++                        flag = wx.ALIGN_CENTER)
++
++        border.Add(item = dialogSizer, proportion = 0,
++                   flag = wx.ALL, border = 5)
++
++        self.SetSizer(border)
++        self.Layout()
++        self.Fit()
++
++        # bindings
++        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++    def _addSelectSizer(self, title, sel): 
++        """!Helper layout function.
++        """
++        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++        selTitleSizer.Add(item = title, proportion = 1,
++                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++        selSizer.Add(item = selTitleSizer, proportion = 0,
++                     flag = wx.EXPAND)
++
++        selSizer.Add(item = sel, proportion = 1,
++                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++                     border = 5)
++
++        return selSizer
++
++    def OnClose(self, event):
++        """!Close dialog
++        """
++        if not self.IsModal():
++            self.Destroy()
++        event.Skip()
++
++    def OnOk(self, event):
++        """!
++        """
++        band_1 = self.band_1_ch.GetSelection()
++        band_2 = self.band_2_ch.GetSelection()
++
++
++        if band_1 == band_2:
++            GError(_("Selected bands must be different."))
++            return
++        
++        #TODO axes selection
++        if band_1 > band_2:
++            tmp_band = band_2
++            band_2 = band_1
++            band_1 = band_2
++
++        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++
++        event.Skip()
++
++    def GetScattId(self):
++        return self.scatt_id
+Index: gui/wxpython/scatt_plot/toolbars_iclass.py
+===================================================================
+--- gui/wxpython/scatt_plot/toolbars_iclass.py	(revision 0)
++++ gui/wxpython/scatt_plot/toolbars_iclass.py	(working copy)
+@@ -0,0 +1,106 @@
++"""!
++ at package scatt_plot.toolbars
++
++ at brief Scatter plot - toolbars
++
++Classes:
++ - toolbars::MainToolbar
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++
++import wx
++
++from icons.icon import MetaIcon
++from gui_core.toolbars import BaseToolbar, BaseIcons
++from core.gcmd import RunCommand
++from core.gcmd import GException, GError, RunCommand
++from scatt_plot.sc_pl_core import idBandsToidScatt
++
++
++class MainToolbar(BaseToolbar):
++    """!Main toolbar
++    """
++    def __init__(self, parent, scatt_mgr):
++        BaseToolbar.__init__(self, parent)
++        self.scatt_mgr = scatt_mgr
++
++        self.InitToolbar(self._toolbarData())
++        
++        # realize the toolbar
++        self.Realize()
++
++    def _toolbarData(self):
++
++        icons = {
++                 'settings'   : BaseIcons['settings'].SetLabel( _('Ssettings')),
++                 'help'       : MetaIcon(img = 'help',
++                                         label = _('Show manual')),
++                 'add_scatt_pl'  : MetaIcon(img = 'layer-raster-analyze',
++                                            label = _('Add scatter plot')),
++                 'editCatAdd'  : MetaIcon(img = 'polygon-create',
++                                          label = _('Add region to category mode')),
++                 'editCatRemove'  : MetaIcon(img = 'polygon-delete',
++                                             label = _('Remove region to category mode')),
++                 'pan'        : MetaIcon(img = 'pan',
++                                         label = _('Pan'),
++                                         desc = _('Drag with mouse to pan scatter plots (zoom with holding right mouse button and draging')),
++                'zoomIn'     : MetaIcon(img = 'zoom-in',
++                                          label = _('Zoom in'),
++                                          desc = _('Zoom with rectangle in scatter plots.')),
++                'cats_mgr' : MetaIcon(img = 'table-manager',
++                                          label = _('Class manager'))
++                }
++
++        return self._getToolbarData((
++                                     ("cats_mgr", icons['cats_mgr'],
++                                     lambda event: self.parent.ShowCategoryPanel(event.Checked()), wx.ITEM_CHECK),
++                                     (None, ),
++                                     ("pan", icons["pan"],
++                                     lambda event: self.SetPloltsMode(event, 'pan'),
++                                      wx.ITEM_CHECK),
++                                     ("zoom", icons["zoomIn"],
++                                     lambda event: self.SetPloltsMode(event, 'zoom'),
++                                      wx.ITEM_CHECK),
++                                     ('add', icons['editCatAdd'],
++                                     lambda event: self.SetPloltsMode(event, 'add'),
++                                     wx.ITEM_CHECK),
++                                     ('remove', icons['editCatRemove'],
++                                     lambda event: self.SetPloltsMode(event, 'remove'),
++                                     wx.ITEM_CHECK),
++                                     (None, ),
++                                     ('add_scatt', icons["add_scatt_pl"],
++                                     lambda event : self.scatt_mgr.AddScattPlot())
++                                     #('settings', icon["settings"],
++                                     # self.parent.OnSettings),  
++                                     #('help', icons["help"],
++                                     # self.OnHelp),                    
++                                    ))
++
++    def GetToolId(self, toolName): #TODO can be useful in base
++
++        return vars(self)[toolName]            
++
++    def SetPloltsMode(self, event, tool_name):
++
++        #TODO move to toolbars
++        if  event.Checked()  == True:
++            for i_tool_data in  self._data:
++                i_tool_name = i_tool_data[0]
++                if  not i_tool_name or i_tool_name == "cats_mgr":
++                    continue
++                if i_tool_name == tool_name:
++                    continue
++                i_tool_id = vars(self)[i_tool_name]
++
++                self.ToggleTool(i_tool_id, False)
++            self.scatt_mgr.SetPlotsMode(mode = tool_name)
++            return
++
++        self.scatt_mgr.SetPlotsMode(mode = None)
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/toolbars.py
+===================================================================
+--- gui/wxpython/scatt_plot/toolbars.py	(revision 0)
++++ gui/wxpython/scatt_plot/toolbars.py	(working copy)
+@@ -0,0 +1,106 @@
++"""!
++ at package scatt_plot.toolbars
++
++ at brief Scatter plot - toolbars
++
++Classes:
++ - toolbars::MainToolbar
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++
++import wx
++
++from icons.icon import MetaIcon
++from gui_core.toolbars import BaseToolbar, BaseIcons
++from core.gcmd import RunCommand
++
++class MainToolbar(BaseToolbar):
++    """!Main toolbar
++    """
++    def __init__(self, parent):
++        BaseToolbar.__init__(self, parent)
++        
++        self.InitToolbar(self._toolbarData())
++        
++        # realize the toolbar
++        self.Realize()
++
++    def _toolbarData(self):
++
++        icons = {
++                 'set_data'    : MetaIcon(img = 'layer-raster-add',
++                                         label = _('Set input raster data for plots')),
++                 'settings'   : BaseIcons['settings'].SetLabel( _('Ssettings')),
++                 'help'       : MetaIcon(img = 'help',
++                                         label = _('Show manual')),
++                 'add_scatt_pl'  : MetaIcon(img = 'layer-raster-analyze',
++                                            label = _('Add scatter plot'))
++                }
++
++        return self._getToolbarData((
++                                     ('sat_data', icons["set_data"],
++                                      self.parent.OnSetData),
++                                     (None, ),
++                                     ('add_scatt', icons["add_scatt_pl"],
++                                      self.parent.OnAddScattPl),
++                                     #('settings', icons["settings"],
++                                     # self.parent.OnSettings),  
++                                     #('help', icons["help"],
++                                     # self.OnHelp),                    
++                                     ("quit", BaseIcons['quit'],
++                                      self.parent.OnCloseDialog)
++                                    ))
++
++    def OnHelp(self, event) :
++            RunCommand('g.manual',
++                       entry = 'wxGUI.scatt_plot')
++
++class CategoriesToolbar(BaseToolbar):
++
++    def __init__(self, parent, cats_list, scatts_dlg):
++        BaseToolbar.__init__(self, parent)
++        self.cats_list = cats_list
++        self.scatts_dlg = scatts_dlg
++
++        self.InitToolbar(self._toolbarData())
++        
++
++        # realize the toolbar
++        self.Realize()
++
++
++    def _toolbarData(self):
++
++        icons = {
++            'editCatAdd'  : MetaIcon(img = 'polygon-create',
++                                     label = _('Add region to category mode')),
++            'editCatRemove'  : MetaIcon(img = 'polygon-delete',
++                                        label = _('Remove region to category mode')),
++            'addCat'     : MetaIcon(img = 'layer-add',
++                                    label = _('Add category')),
++            'deleteCat'  : MetaIcon(img = 'layer-remove',
++                                    label = _('Delete category'))
++            }
++
++        return  self._getToolbarData((('editCatAdd', icons['editCatAdd'],
++                                        lambda event: self.scatts_dlg.EditCatAdd(),
++                                        wx.ITEM_CHECK),
++                                      ('editCatRemove', icons['editCatRemove'],
++                                        lambda event: self.scatts_dlg.EditCatRemove(),
++                                        wx.ITEM_CHECK),
++                                     (None, ),
++                                     ('addCat', icons["addCat"],
++                                        lambda event: self.cats_list.AddCategory()),
++                                     ('deleteCat', icons["deleteCat"],
++                                        lambda event: self.cats_list.DeleteCategory())))
++                                    
++    def GetToolId(self, toolName): #TODO can be useful in base
++
++        return vars(self)[toolName]            
+\ No newline at end of file
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57453)
++++ gui/wxpython/mapdisp/toolbars.py	(working copy)
+@@ -239,7 +239,8 @@
+                       (MapIcons["scatter"],     self.parent.OnScatterplot),
+                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
+                       (BaseIcons["histogramD"], self.parent.OnHistogram),
+-                      (MapIcons["vnet"],        self.parent.OnVNet)))
++                      (MapIcons["vnet"],        self.parent.OnVNet),
++                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
          
-+        self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
-         return True
+     def OnDecoration(self, event):
+         """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py	(revision 57453)
++++ gui/wxpython/mapdisp/frame.py	(working copy)
+@@ -225,6 +225,7 @@
+         #
+         self.dialogs = {}
+         self.dialogs['attributes'] = None
++        self.dialogs['scatt_plot'] = None
+         self.dialogs['category'] = None
+         self.dialogs['barscale'] = None
+         self.dialogs['legend'] = None
+@@ -1168,6 +1169,19 @@
+         """!Returns toolbar with zooming tools"""
+         return self.toolbars['map']
  
-     def StopEditing(self):
++    def OnScatterplot2(self, event):
++        """!Init interactive scatterplot tools
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
++
++        from scatt_plot.dialogs import ScattPlotMainDialog
++        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++        
++        self.dialogs['scatt_plot'].CenterOnScreen()
++        self.dialogs['scatt_plot'].Show()
++
+     def OnVNet(self, event):
+         """!Dialog for v.net* modules 
+         """
 Index: gui/wxpython/vdigit/wxdigit.py
 ===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57437)
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57453)
 +++ gui/wxpython/vdigit/wxdigit.py	(working copy)
 @@ -17,7 +17,7 @@
  (and NumPy would be an excellent candidate for acceleration via
@@ -3178,7 +2784,7 @@
          """!Delete selected features
  
 @@ -434,16 +451,27 @@
-         # colect categories for delete if requested
+         # collect categories for deleting if requested
          deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
          catDict = dict()
 +
@@ -3210,7 +2816,7 @@
          poList = self._display.GetSelectedIList()
          nlines = Vedit_delete_lines(self.poMapInfo, poList)
 @@ -456,7 +484,8 @@
-                 self._deleteRecords(cats)
+                 self._deleteRecords(catDict)
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
@@ -3543,7 +3149,7 @@
          return newline
  
      def FlipLine(self):
-@@ -1510,26 +1753,52 @@
+@@ -1514,26 +1757,52 @@
              return 0
          
          poList  = self._display.GetSelectedIList()
@@ -3598,57 +3204,374 @@
          return 1
      
      def GetLineCats(self, line):
-Index: gui/wxpython/mapdisp/toolbars.py
+Index: gui/wxpython/vdigit/toolbars.py
 ===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57437)
-+++ gui/wxpython/mapdisp/toolbars.py	(working copy)
-@@ -239,7 +239,8 @@
-                       (MapIcons["scatter"],     self.parent.OnScatterplot),
-                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
-                       (BaseIcons["histogramD"], self.parent.OnHistogram),
--                      (MapIcons["vnet"],        self.parent.OnVNet)))
-+                      (MapIcons["vnet"],        self.parent.OnVNet),
-+                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
+--- gui/wxpython/vdigit/toolbars.py	(revision 57453)
++++ gui/wxpython/vdigit/toolbars.py	(working copy)
+@@ -17,6 +17,7 @@
+ import wx
+ 
+ from grass.script import core as grass
++from grass.pydispatch.signal import Signal
+ 
+ from gui_core.toolbars  import BaseToolbar, BaseIcons
+ from gui_core.dialogs   import CreateNewVector
+@@ -42,6 +43,8 @@
+         self.digit         = None
+         self._giface       = giface
          
-     def OnDecoration(self, event):
-         """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
++        self.editingStarted = Signal("VDigitToolbar.editingStarted")
++
+         # currently selected map layer for editing (reference to MapLayer instance)
+         self.mapLayer = None
+         # list of vector layers from Layer Manager (only in the current mapset)
+@@ -860,6 +863,7 @@
+             alpha = int(opacity * 255)
+             self.digit.GetDisplay().UpdateSettings(alpha = alpha)
+         
++        self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
+         return True
+ 
+     def StopEditing(self):
+Index: gui/wxpython/Makefile
 ===================================================================
---- gui/wxpython/mapdisp/frame.py	(revision 57437)
-+++ gui/wxpython/mapdisp/frame.py	(working copy)
-@@ -226,6 +226,7 @@
+--- gui/wxpython/Makefile	(revision 57453)
++++ gui/wxpython/Makefile	(working copy)
+@@ -13,7 +13,7 @@
+ 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
+ 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
+ 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* vdigit/* \
+-	vnet/*.py web_services/*.py wxplot/*.py) \
++	vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
+ 	gis_set.py gis_set_error.py wxgui.py README
+ 
+ DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
+@@ -21,7 +21,7 @@
+ 
+ PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
+ 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
+-	mapswipe vdigit wxplot web_services rlisetup vnet)
++	mapswipe vdigit wxplot web_services rlisetup vnet scatt_plot)
+ 
+ DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
+ 
+Index: gui/wxpython/iclass/dialogs.py
+===================================================================
+--- gui/wxpython/iclass/dialogs.py	(revision 57453)
++++ gui/wxpython/iclass/dialogs.py	(working copy)
+@@ -333,13 +333,19 @@
+         toolbar.SetCategories(catNames = catNames, catIdx = cats)
+         if name in catNames:
+             toolbar.choice.SetStringSelection(name)
++            cat = toolbar.GetSelectedCategoryIdx()
+         elif catNames:
+             toolbar.choice.SetSelection(0)
+-            
++            cat = toolbar.GetSelectedCategoryIdx()
++        else:
++            cat = None
++
+         if toolbar.choice.IsEmpty():
+             toolbar.EnableControls(False)
+         else:
+             toolbar.EnableControls(True)
++
++        self.mapWindow.CategoryChanged(cat)
+         # don't forget to update maps, histo, ...
+         
+     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
+Index: gui/wxpython/iclass/toolbars.py
+===================================================================
+--- gui/wxpython/iclass/toolbars.py	(revision 57453)
++++ gui/wxpython/iclass/toolbars.py	(working copy)
+@@ -46,9 +46,7 @@
+         'importAreas' : MetaIcon(img = 'layer-import',
+                             label = _('Import training areas from vector map')),
+         'addRgb' : MetaIcon(img = 'layer-rgb-add',
+-                            label = _('Add RGB map layer')),
+-        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
+-                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
++                            label = _('Add RGB map layer'))
+         }
+         
+ class IClassMapToolbar(BaseToolbar):
+@@ -117,10 +115,7 @@
+                                      ("zoomBack", icons["zoomBack"],
+                                       self.parent.OnZoomBack),
+                                      ("zoomToMap", icons["zoomExtent"],
+-                                      self.parent.OnZoomToMap),
+-                                     (None, ),
+-                                     ("scatt_plot", iClassIcons["scatt_plot"],
+-                                      self.parent.OnScatterplot)
++                                      self.parent.OnZoomToMap)
+                                     ))
+ class IClassToolbar(BaseToolbar):
+     """!IClass toolbar
+@@ -156,7 +151,7 @@
+         """!Toolbar data"""
+         icons = iClassIcons
+         return self._getToolbarData((("selectGroup", icons['selectGroup'],
+-                                      self.parent.OnAddBands),
++                                      lambda event : self.parent.AddBands()),
+                                       (None, ),
+                                       ("classManager", icons['classManager'],
+                                       self.parent.OnCategoryManager),
+Index: gui/wxpython/iclass/frame.py
+===================================================================
+--- gui/wxpython/iclass/frame.py	(revision 57453)
++++ gui/wxpython/iclass/frame.py	(working copy)
+@@ -64,6 +64,8 @@
+                                IClassExportAreasDialog, IClassMapDialog
+ from iclass.plots       import PlotPanel
+ 
++from grass.pydispatch.signal import Signal
++
+ class IClassMapFrame(DoubleMapFrame):
+     """! wxIClass main frame
+     
+@@ -114,6 +116,10 @@
+             lambda:
+             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
+         self.SetSize(size)
++
++        self.groupSet = Signal("IClassMapFrame.groupSet")
++        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
++
          #
-         self.dialogs = {}
-         self.dialogs['attributes'] = None
-+        self.dialogs['scatt_plot'] = None
-         self.dialogs['category'] = None
-         self.dialogs['barscale'] = None
-         self.dialogs['legend'] = None
-@@ -1173,6 +1174,19 @@
-         """!Returns toolbar with zooming tools"""
-         return self.toolbars['map']
+         # Add toolbars
+         #
+@@ -177,7 +183,7 @@
+         self.dialogs['category']   = None
+         
+         # PyPlot init
+-        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
++        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
+                                    
+         self._addPanes()
+         self._mgr.Update()
+@@ -237,7 +243,7 @@
+             return False
+         
+         return vectorName
+-        
++    
+     def RemoveTempVector(self):
+         """!Removes temporary vector map with training areas"""
+         ret = RunCommand(prog = 'g.remove',
+@@ -477,7 +483,7 @@
+         
+         self.Render(self.GetFirstWindow())
+         
+-    def OnAddBands(self, event):
++    def AddBands(self):
+         """!Add imagery group"""
+         dlg = IClassGroupDialog(self, group = self.group)
+         if dlg.ShowModal() == wx.ID_OK:
+@@ -488,7 +494,8 @@
+         """!Set imagery group"""
+         group = grass.find_file(name = name, element = 'group')
+         if group['name']:
+-            self.group = group['name']
++           self.group = group['name']
++           self.groupSet.emit(group = group['name'])
+         else:
+             GError(_("Group <%s> not found") % name, parent = self)
+     
+@@ -768,17 +775,20 @@
+         
+         Updates number of stddev, histograms, layer in preview display. 
+         """
+-        stat = self.stats_data.GetStatistics(currentCat)
+-        nstd = stat.nstd
+-        self.toolbars['iClass'].UpdateStddev(nstd)
+-        
+-        self.plotPanel.UpdateCategory(currentCat)
+-        self.plotPanel.OnPlotTypeSelected(None)
++        if currentCat:
++          stat = self.stats_data.GetStatistics(currentCat)
++          nstd = stat.nstd
++          self.toolbars['iClass'].UpdateStddev(nstd)
++          
++          self.plotPanel.UpdateCategory(currentCat)
++          self.plotPanel.OnPlotTypeSelected(None)
+                                    
+-        name = stat.rasterName
+-        name = self.previewMapManager.GetAlias(name)
+-        if name:
+-            self.previewMapManager.SelectLayer(name)
++          name = stat.rasterName
++          name = self.previewMapManager.GetAlias(name)
++          if name:
++              self.previewMapManager.SelectLayer(name)
++
++        self.categoryChanged.emit(cat = currentCat)
+         
+     def DeleteAreas(self, cats):
+         """!Removes all training areas of given categories
+@@ -1105,27 +1115,6 @@
+         self.GetFirstWindow().SetModePointer()
+         self.GetSecondWindow().SetModePointer()
  
-+    def OnScatterplot2(self, event):
+-    def OnScatterplot(self, event):
+-        """!Init interactive scatterplot tools
+-        """
+-        if self.dialogs['scatt_plot']:
+-            self.dialogs['scatt_plot'].Raise()
+-            return
+-
+-        try:
+-          from scatt_plot.dialogs import ScattPlotMainDialog
+-        except:
+-          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
+-          return
+-
+-        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
+-
+-        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
+-        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
+-
+-        self.dialogs['scatt_plot'].CenterOnScreen()
+-        self.dialogs['scatt_plot'].Show()
+-
+ class MapManager:
+     """! Class for managing map renderer.
+     
+Index: gui/wxpython/iclass/plots.py
+===================================================================
+--- gui/wxpython/iclass/plots.py	(revision 57453)
++++ gui/wxpython/iclass/plots.py	(working copy)
+@@ -28,7 +28,7 @@
+     for each band and for one category. Coincidence plots show min max range
+     of classes for each band.
+     """
+-    def __init__(self, parent, stats_data):
++    def __init__(self, parent, giface, stats_data):
+         scrolled.ScrolledPanel.__init__(self, parent)
+         
+         self.SetupScrolling(scroll_x = False, scroll_y = True)
+@@ -38,26 +38,62 @@
+         self.stats_data = stats_data
+         self.currentCat = None
+         
++        self._giface = giface
++
+         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+-        
++
+         self._createControlPanel()
+-        
++        self._createPlotPanel()
++        self._createScatterPlotPanel()
++
+         self.SetSizer(self.mainSizer)
+         self.mainSizer.Fit(self)
+         self.Layout()
+         
++    def _createPlotPanel(self):
++
++        self.canvasPanel = wx.Panel(parent=self)
++        self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
++        self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
++        self.canvasPanel.SetSizer(self.canvasSizer)
++
+     def _createControlPanel(self):
+         self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
+                                      choices = [_("Histograms"),
+-                                                _("Coincident plots")])
++                                                _("Coincident plots"),
++                                                _("Scatter plots")])
+         self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
+         self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
+-        
++    
++    def _createScatterPlotPanel(self):
 +        """!Init interactive scatterplot tools
 +        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
++        try:
++            from scatt_plot.dialogs_iclass import IClassScatterPlotsPanel
++            self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, giface=self._giface, iclass_mapwin = self.parent.GetFirstWindow())
++            self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
++            self.scatt_plot_panel.Hide()
++        except ImportError as e:
++            self.scatt_plot_panel = None
 +
-+        from scatt_plot.dialogs import ScattPlotMainDialog
-+        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
-+        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
+     def OnPlotTypeSelected(self, event):
+         """!Plot type selected"""
 +
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
++        if self.plotSwitch.GetSelection() in [0, 1]:
++            self.SetupScrolling(scroll_x = False, scroll_y = True)
++            self.scatt_plot_panel.Hide()
++            self.canvasPanel.Show()
++            self.Layout()
++
++        elif self.plotSwitch.GetSelection() == 2:
++            self.SetupScrolling(scroll_x = False, scroll_y = False)
++            self.scatt_plot_panel.Show()
++            self.canvasPanel.Hide()
++            self.Layout()
++
+         if self.currentCat is None:
+             return
+-        
++
+         if self.plotSwitch.GetSelection() == 0:
+             stat = self.stats_data.GetStatistics(self.currentCat)
+             if not stat.IsReady():
+@@ -66,7 +102,10 @@
+             self.DrawHistograms(stat)
+         else:
+             self.DrawCoincidencePlots()
+-            
++
++        self.Layout()
++
++
+     def StddevChanged(self):
+         """!Standard deviation multiplier changed, redraw histograms"""
+         if self.plotSwitch.GetSelection() == 0:
+@@ -89,7 +128,7 @@
+             panel.Destroy()
+             
+         self.canvasList = []
+-            
++
+     def ClearPlots(self):
+         """!Clears plot canvases"""
+         for bandIdx in range(len(self.bandList)):
+@@ -104,15 +143,15 @@
+     def CreatePlotCanvases(self):
+         """!Create plot canvases according to the number of bands"""
+         for band in self.bandList:
+-            canvas = plot.PlotCanvas(self)
++            canvas = plot.PlotCanvas(self.canvasPanel)
+             canvas.SetMinSize((-1, 140))
+             canvas.SetFontSizeTitle(10)
+             canvas.SetFontSizeAxis(8)
+             self.canvasList.append(canvas)
+             
+-            self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
+-
+-        self.SetVirtualSize(self.GetBestVirtualSize()) 
++            self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
++        
++        self.SetVirtualSize(self.GetBestVirtualSize())
+         self.Layout()
+         
+     def UpdatePlots(self, group, currentCat, stats_data):
+@@ -138,7 +177,7 @@
+         
+     def UpdateCategory(self, cat):
+         self.currentCat = cat
+-        
++    
+     def DrawCoincidencePlots(self):
+         """!Draw coincidence plots"""
+         for bandIdx in range(len(self.bandList)):
 Index: lib/imagery/scatt_sccats.c
 ===================================================================
 --- lib/imagery/scatt_sccats.c	(revision 0)
 +++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,421 @@
+@@ -0,0 +1,405 @@
 +/*!
 +   \file lib/imagery/scatt_cat_rast.c
 +
@@ -3674,42 +3597,58 @@
 +/*!
 +   \brief Compute band ids from scatter plot id.
 +
++    Scatter plot id describes which bands defines the scatter plot.
++
++    Let say we have 3 bands, their ids are 0, 1 and 2.
++    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
++    All scatter plots:
++    scatt_id b_1_id b_2_id
++    0        0      1
++    1        0      2
++    2        1      2
++
 +   \param scatt_id scatter plot id
 +   \param n_bands number of bands
-+   \param [out] band_1 id of band1
-+   \param[out] band_2 id of band2
++   \param [out] b_1_id id of band1
++   \param[out] b_2_id id of band2
++
++   \return 0
 + */
-+static void id_scatt_to_bands(const int scatt_id, const int n_bands, int * band_1, int * band_2)
++int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
 +{   
 +    int n_b1 = n_bands - 1;
 +
-+    * band_1 = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
++    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
 +
-+    * band_2 = scatt_id - ((* band_1) * (2 * n_b1 + 1) - (* band_1) * (* band_1)) / 2 + (* band_1) + 1;
++    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
 +
-+    return;
++    return 0;
 +}
 +
 +
 +/*!
 +   \brief Compute scatter plot id from band ids.
 +
++    See also I_id_scatt_to_bands().
++
 +   \param n_bands number of bands
-+   \param band_1 id of band1
-+   \param band_2 id of band2
++   \param b_1_id id of band1
++   \param b_1_id id of band2
 +   \param [out] scatt_id scatter plot id
++
++   \return 0
 + */
-+static void bands_to_id_scatt(const int band_1, const int band_2, const int n_bands, int * scatt_id)
++int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
 +{   
 +    int n_b1 = n_bands - 1;
 +
-+    * scatt_id = (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_2 - band_1 - 1;
++    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
 +
-+    return;
++    return 0;
 +}
 +
 +/*!
-+   \brief Initialize structury for soring scatter plots data.
++   \brief Initialize structure for storing scatter plots data.
 +
 +   \param cats pointer to scCats struct 
 +   \param n_bands number of bands
@@ -3741,7 +3680,7 @@
 +}
 +
 +/*!
-+   \brief Free date of struct scCats, the structure itself remains alocated.   .
++   \brief Free data of struct scCats, the structure itself remains alocated.
 +
 +   \param cats pointer to existing scCats struct
 + */
@@ -3774,40 +3713,37 @@
 +}
 +
 +#if 0
-+
 +void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
 +{
 +    a_cats_ids = cats->cats_ids;
 +    * n_a_cats = cats->n_a_cats;
 +}
-+
 +#endif
++
 +/*!
 +   \brief Add category.
 +    
 +    Category represents group of scatter plots.
 +
 +   \param cats pointer to scCats struct
-+   \param cat_id number id of category.
 +
-+   \return -2 value if id is over limit
-+   \return -1 category id is invalid
-+   \return  0 category was added 
++   \return assigned category id (starts with 0)
++   \return -1 if maximum nuber of categories was reached
 + */
-+int I_sc_add_cat(struct scCats * cats, int cat_id)
++int I_sc_add_cat(struct scCats * cats)
 +{
-+    int i_scatt;
++    int i_scatt, i_cat_id, cat_id;
 +    int n_a_cats = cats->n_a_cats;
 +
-+    if(cat_id < 0 || cat_id > cats->n_cats)
++    if(cats->n_a_cats >= cats->n_cats)
 +        return -1;
 +
-+    if(cat_id >= cats->n_cats)
-+        return -2;
++    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
++        if(cats->cats_idxs[i_cat_id] < 0) {
++            cat_id = i_cat_id;
++            break;
++        }
 +
-+    if(cats->cats_idxs[cat_id] >= 0) 
-+        return -1;
-+
 +    cats->cats_ids[n_a_cats] = cat_id;
 +    cats->cats_idxs[cat_id] = n_a_cats;
 +    
@@ -3826,7 +3762,7 @@
 +    
 +    ++cats->n_a_cats;
 +
-+    return 0;
++    return cat_id;
 +}
 +
 +#if 0
@@ -3899,7 +3835,7 @@
 +
 +    scatts->scatt_idxs[scatt_id] = n_a_scatts;
 +
-+    id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
++    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
 +
 +    scatts->scatts_bands[n_a_scatts * 2] = band_1;
 +    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
@@ -3970,31 +3906,17 @@
 +#endif
 +
 +/*!
-+   \brief Insert scatter plot data .
++   \brief Insert scatter plot data.
 +    
 +   \param scatt_data pointer to existing struct scdScattData
 +   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
 +   \param n_vals number of data values
 +   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
-+   \param band_1_range data range of band1
-+   \param band_2_range data range of band2
-+
-+   \return  0 on success
-+   \return -1 on failure
 + */
-+void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data, 
-+                           struct Range band_1_range, struct Range band_2_range)
++void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
 +{
 +    scatt_data->n_vals = n_vals;
 +
-+    scatt_data->band_1_range.min = band_1_range.min;
-+    scatt_data->band_1_range.max = band_1_range.max;
-+    scatt_data->band_1_range.first_time = 0;
-+
-+    scatt_data->band_2_range.min = band_2_range.min;
-+    scatt_data->band_2_range.max = band_2_range.max;
-+    scatt_data->band_2_range.first_time = 0;
-+
 +    if(type == SC_SCATT_DATA)
 +    {   
 +        if(data)
@@ -4019,22 +3941,7 @@
 +    return;
 +}
 +
-+/*!
-+   \brief Free members of scdScattData struct.
 +
-+   \param scatt_data struct scdScattData to be freed
-+ */
-+void I_scd_free_scatt_data(struct scdScattData * scatt_data)
-+{
-+
-+    G_free(scatt_data->b_conds_arr);
-+    G_free(scatt_data->scatt_vals_arr);
-+
-+    scatt_data = NULL;
-+
-+    return;
-+}
-+
 +#if 0
 +void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
 +{
@@ -4074,7 +3981,7 @@
 ===================================================================
 --- lib/imagery/scatt.c	(revision 0)
 +++ lib/imagery/scatt.c	(working copy)
-@@ -0,0 +1,696 @@
+@@ -0,0 +1,745 @@
 +/*!
 +   \file lib/imagery/scatt.c
 +
@@ -4093,6 +4000,7 @@
 +#include <grass/raster.h>
 +#include <grass/imagery.h>
 +#include <grass/gis.h>
++#include <grass/glocale.h>
 +
 +#include <stdio.h>
 +#include <stdlib.h>
@@ -4100,23 +4008,30 @@
 +#include <string.h>
 +
 +
++struct rast_row
++{
++    CELL * row;
++    char * null_row;
++    struct Range rast_range; /*Range of whole raster.*/
++};
++
 +/*!
 +   \brief Create pgm header.
 +
-+   Scatter plot internally generates pgm files. These pns has header in format created by this function.
++   Scatter plot internally generates pgm files. These pgms have header in format created by this function.
 +    
-+   \param region - region to be pgm header generated for 
-+   \param [out] header - header pgm
++   \param region region to be pgm header generated for 
++   \param [out] header header of pgm file
 + */
 +static int get_cat_rast_header(struct Cell_head * region, char * header){
 +    return sprintf(header, "P5\n%d\n%d\n1\n", region->cols, region->rows);
 +}
 +
 +/*!
-+   \brief Create pgm file.
-+
-+   \param cat_rast_region - region to be file generated for
-+   \param cat_rast - path of pgm file
++   \brief Create category raster conditions file.
++    
++   \param cat_rast_region region to be file generated for
++   \param cat_rast path of generated category raster file
 + */
 +int I_create_cat_rast(struct Cell_head * cat_rast_region,  const char * cat_rast)
 +{
@@ -4128,14 +4043,17 @@
 +    unsigned char * row_data;
 +
 +    f_cat_rast = fopen(cat_rast, "wb");
-+    if(!f_cat_rast)
++    if(!f_cat_rast) {
++        G_warning("Unable to create category raster condition file <%s>.", cat_rast);
 +        return -1;
++    }
 +
 +    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
 +
 +    fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
 +    if (ferror(f_cat_rast)){
 +        fclose(f_cat_rast);
++        G_warning(_("Unable to write header into category raster condition file <%s>."), cat_rast);
 +        return -1;
 +    }
 +
@@ -4148,7 +4066,7 @@
 +        if (ferror(f_cat_rast))
 +        {
 +            fclose(f_cat_rast);
-+            G_debug(3, "Unable to write into file.");
++            G_warning(_("Unable to write into category raster condition file <%s>."), cat_rast);
 +            return -1;
 +        }
 +    }
@@ -4157,9 +4075,9 @@
 +    return 0;
 +}
 +
-+static int print_reg(struct Cell_head * intersec, const char * pref)
++static int print_reg(struct Cell_head * intersec, const char * pref, int dbg_level)
 +{
-+    G_debug(0, "%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south, 
++    G_debug(dbg_level, "%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south, 
 +               intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
 +}
 +
@@ -4168,7 +4086,7 @@
 +
 +   \param A pointer to intersected region
 +   \param B pointer to intersected region
-+   \param [out] intersec pointer to intersection region of regions A B ( valid params of the region are: south, north, east, west)
++   \param [out] intersec pointer to intersection region of regions A B (relevant params of the region are: south, north, east, west)
 +
 +   \return  0 if interection exists
 +   \return -1 if regions does not intersect
@@ -4204,12 +4122,13 @@
 +   \brief Get rows and cols numbers, which defines intersection of the regions.
 +  
 +   \param A pointer to intersected region
-+   \param B pointer to intersected region
++   \param B pointer to intersected region (A and B must have same resolution)
 +   \param [out] A_bounds rows and cols numbers of A stored in south, north, east, west, which defines intersection of A and B
-+   \param [out] A_bounds rows and cols numbers of B stored in south, north, east, west, which defines intersection of A and B
++   \param [out] B_bounds rows and cols numbers of B stored in south, north, east, west, which defines intersection of A and B
 +
 +   \return  0 if interection exists
 +   \return -1 if regions do not intersect
++   \return -2 resolution of regions is not same 
 +*/
 +static int get_rows_and_cols_bounds(struct Cell_head * A,  struct Cell_head * B, struct Cell_head * A_bounds,  struct Cell_head * B_bounds)
 +{
@@ -4219,13 +4138,13 @@
 +
 +    /* TODO is it right check? */
 +    if(abs(A->ns_res - B->ns_res) > GRASS_EPSILON) {
-+        G_debug(0, "'get_rows_and_cols_bounds' ns_res does not fit diff: %.20f", A->ew_res - B->ew_res);
-+        return -1;
++        G_debug(0, "'get_rows_and_cols_bounds' ns_res does not fit, A->ns_res: %f B->ns_res: %f", A->ns_res, B->ns_res);
++        return -2;
 +    }
 +
 +    if(abs(A->ew_res - B->ew_res) > GRASS_EPSILON) {
-+        G_debug(0, "'get_rows_and_cols_bounds' ew_res does not fit diff: %.20f", A->ew_res - B->ew_res);
-+        return -1;
++        G_debug(0, "'get_rows_and_cols_bounds' ew_res does not fit, A->ew_res: %f B->ew_res: %f", A->ew_res, B->ew_res);
++        return -2;
 +    }
 +
 +    ns_res = A->ns_res;
@@ -4253,8 +4172,8 @@
 +   \brief Insert raster map patch into pgm file.
 +  
 +   \param patch_rast name of raster map
-+   \param cat_rast_region region of pgm file
-+   \param cat_rast path to pgm file
++   \param cat_rast_region region of category raster file
++   \param cat_rast path to category raster file
 +
 +   \return  0 on success
 +   \return -1 on failure
@@ -4266,13 +4185,12 @@
 +    struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
 +    char cat_rast_header[1024];//TODO magic number 
 +    int i_row, i_col, ncols, nrows, cat_rast_col, patch_col, val;
-+    int head_nchars;
++    int head_nchars, ret;
 +    int fd_patch_rast, init_shift, step_shift;
 +    unsigned char * patch_data;
 +
 +    char * null_chunk_row;
 +
-+    //TODO G_free mapset (also in compute  scatts)
 +    const char *mapset;
 +
 +    struct Cell_head patch_lines, cat_rast_lines;
@@ -4280,14 +4198,15 @@
 +    unsigned char * row_data;
 +
 +    f_cat_rast = fopen(cat_rast, "rb+");
-+    if(!f_cat_rast)
++    if(!f_cat_rast) {
++        G_warning(_("Unable to open category raster condtions file <%s>."), cat_rast);
 +        return -1;
-+    
-+    /* TODO */
-+    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++    }
 +
-+    if ((mapset = G_find_raster2(patch_rast,"")) == NULL) {
++    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++    if ((mapset = G_find_raster(patch_rast,"")) == NULL) {
 +        fclose(f_cat_rast);
++        G_warning(_("Unable to find patch raster <%s>."), patch_rast);
 +        return -1;
 +    }
 +
@@ -4299,10 +4218,23 @@
 +        return -1;
 +    }
 +
-+    null_chunk_row =  Rast_allocate_null_buf();
++    ret = get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds);
++    if(ret == -2) { 
++        G_warning(_("Resolutions of patch <%s> and patched file <%s> are not same."), patch_rast, cat_rast);
 +
-+    if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
++        Rast_close(fd_patch_rast);
++        fclose(f_cat_rast);
 +
++        return -1;
++    }
++    else if (ret == -1){
++
++        Rast_close(fd_patch_rast);
++        fclose(f_cat_rast);
++
++        return 0;
++    }
++
 +    ncols = cat_rast_bounds.east - cat_rast_bounds.west;
 +    nrows = cat_rast_bounds.south - cat_rast_bounds.north;
 +
@@ -4311,11 +4243,18 @@
 +    init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
 +
 +    if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
-+        G_message("seek failed");
++        G_warning(_("Corrupted  category raster conditions file <%s> (fseek failed)"), cat_rast);
++
++        Rast_close(fd_patch_rast);
++        G_free(null_chunk_row);
++        fclose(f_cat_rast);
++
 +        return -1;
 +    }
 +
 +    step_shift = cat_rast_region->cols - ncols;
++
++    null_chunk_row =  Rast_allocate_null_buf();
 +    
 +    for(i_row = 0; i_row < nrows; i_row++) {
 +        Rast_get_null_value_row (fd_patch_rast, null_chunk_row, i_row + patch_bounds.north);
@@ -4333,12 +4272,21 @@
 +        fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
 +        if (ferror(f_cat_rast))
 +        {
++            G_warning(_("Unable to write into category raster conditions file <%s>"), cat_rast);
++            
++            Rast_close(fd_patch_rast);
 +            G_free(null_chunk_row);
 +            fclose(f_cat_rast);
++
 +            return -1;
 +        }
 +        if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
-+            G_message("seek failed");
++            G_warning(_("Corrupted  category raster conditions file <%s> (fseek failed)"), cat_rast);
++            
++            Rast_close(fd_patch_rast);
++            G_free(null_chunk_row);
++            fclose(f_cat_rast);
++            
 +            return -1;
 +        }
 +    }
@@ -4352,52 +4300,60 @@
 +/*!
 +   \brief Updates scatter plots data in category by pixels which meets category conditions.
 +  
-+   \param chunk_rows data arrays of chunk_rows from analyzed raster bands (all data in chunk_rows, null_chunk_rows and belongs_pix arrays represents same region)
-+   \param null_chunk_rows null data arrays of chunk_rows from analyzed raster bands
-+   \param chunk_row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
++   \param bands_rows data represents data describig one row from raster band
 +   \param belongs_pix array which defines which pixels belongs to category (1 value) and which not (0 value)
-+   \param scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
++   \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, which are modified according to values in belongs_pix
 +*/
-+static inline void update_cat_scatt_plts(CELL ** chunk_rows, char ** null_chunk_rows, int chunk_row_size, unsigned short * belongs_pix, struct scScatts * scatts)
++static inline void update_cat_scatt_plts(struct rast_row * bands_rows, unsigned short * belongs_pix, struct scScatts * scatts)
 +{
 +    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
 +
-+    CELL * b_1_chunk_rows;
-+    CELL * b_2_chunk_rows;
-+    char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
++    CELL * b_1_row;
++    CELL * b_2_row;
++    char * b_1_null_row,* b_2_null_row;
++    struct rast_row b_1_rast_row, b_2_rast_row;
 +
 +    struct Range b_1_range, b_2_range;
 +    int b_1_range_size;
 +
++    int row_size = Rast_window_cols();
++
 +    int * scatts_bands = scatts->scatts_bands;
 +
 +    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
 +    {   
-+        b_1_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2]];
-+        b_2_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++        b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
++        b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
 +
-+        band_1_null_chunk_rows =  null_chunk_rows[scatts_bands[i_scatt * 2]];
-+        band_2_null_chunk_rows =  null_chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++        b_1_row = b_1_rast_row.row;
++        b_2_row = b_2_rast_row.row;
 +
-+        b_1_range = scatts->scatts_arr[i_scatt]->band_1_range;
-+        b_2_range = scatts->scatts_arr[i_scatt]->band_2_range;
++        b_1_null_row =  b_1_rast_row.null_row;
++        b_2_null_row =  b_2_rast_row.null_row;
 +
++        b_1_range = b_1_rast_row.rast_range;
++        b_2_range = b_2_rast_row.rast_range;
++        
 +        b_1_range_size = b_1_range.max - b_1_range.min + 1;
 +        max_arr_idx = (b_1_range.max -  b_1_range.min + 1) * (b_2_range.max -  b_2_range.min + 1);
 +
-+        for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++        for(i_chunk_rows_pix = 0; i_chunk_rows_pix < row_size; i_chunk_rows_pix++)
 +        {
++            /* pixel does not belongs to scatter plot or has null value in one of the bands */
 +            if(!belongs_pix[i_chunk_rows_pix] || 
-+                band_1_null_chunk_rows[i_chunk_rows_pix] == 1 || 
-+                band_2_null_chunk_rows[i_chunk_rows_pix] == 1)                
++                b_1_null_row[i_chunk_rows_pix] == 1 || 
++                b_2_null_row[i_chunk_rows_pix] == 1)                
 +                continue;
 +
-+            array_idx = b_1_chunk_rows[i_chunk_rows_pix] - b_1_range.min + (b_2_chunk_rows[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
++            /* index in scatter plot array */
++            array_idx = b_1_row[i_chunk_rows_pix] - b_1_range.min + (b_2_row[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
 +
 +            if(array_idx < 0 || array_idx >= max_arr_idx) {
-+                G_warning ("pixel out of range");
++                        G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
 +                continue;
 +            }
++
++            /* increment scatter plot value */
 +            ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
 +        }
 +    }
@@ -4411,26 +4367,27 @@
 +
 +   \param chunk_rows data arrays of chunk_rows from analyzed raster bands (all data in chunk_rows, null_chunk_rows and belongs_pix arrays represents same region)
 +   \param null_chunk_rows null data arrays of chunk_rows from analyzed raster bands
-+   \param chunk_row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
-+   \param f_cats_rasts_conds pgm file which stores selected areas (conditions) from mapwindow 
++   \param row_size size of data in chunk_rows, null_chunk_rows and belongs_pix arrays
++   \param f_cats_rasts_conds file which stores selected areas (conditions) from mapwindow see I_create_cat_rast() and I_pa
 +   \param fd_cats_rasts array of openedraster maps which represents all selected pixels for category
 +   \param region analysis region
 +
 +   \return  0 on success
 +   \return -1 on failure
 +*/
-+static inline int compute_scatts_from_chunk_row(struct scCats * scatts, struct scCats * scatt_conds, 
-+                                                CELL ** chunk_rows, char ** null_chunk_rows, int chunk_row_size, FILE ** f_cats_rasts_conds,
-+                                                int * fd_cats_rasts, struct Cell_head *region)
++static inline int compute_scatts_from_chunk_row(struct Cell_head *region, struct scCats * scatt_conds, 
++                                                FILE ** f_cats_rasts_conds, struct rast_row * bands_rows, 
++                                                struct scCats * scatts, int * fd_cats_rasts)
 +{
 +
-+    int i_chunk_rows_pix, i_cat, i_scatt, n_a_scatts, i_cond;
++    int i_rows_pix, i_cat, i_scatt, n_a_scatts, n_pixs;
 +    int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
-+    char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
++    char * b_1_null_row,* b_2_null_row;
++    struct rast_row b_1_rast_row, b_2_rast_row;
 +    CELL * cat_rast_row;
 +
 +    struct scScatts * scatts_conds;
-+    struct scScatts * scatt_plts_scatts;
++    struct scScatts * scatts_scatt_plts;
 +    struct scdScattData * conds;
 +
 +    struct Range b_1_range, b_2_range;
@@ -4439,14 +4396,17 @@
 +    int * scatts_bands;
 +    struct scdScattData ** scatts_arr;
 +
-+    CELL * b_1_chunk_rows;
-+    CELL * b_2_chunk_rows;
++    CELL * b_1_row;
++    CELL * b_2_row;
 +    unsigned char * i_scatt_conds;
 +
-+    unsigned short * belongs_pix = (unsigned short *) G_malloc(chunk_row_size * sizeof(unsigned short)); 
-+    unsigned char * rast_pixs = (unsigned char *) G_malloc(chunk_row_size * sizeof(unsigned char));
++    int row_size = Rast_window_cols();
++
++    unsigned short * belongs_pix = (unsigned short *) G_malloc(row_size * sizeof(unsigned short)); 
++    unsigned char * rast_pixs = (unsigned char *) G_malloc(row_size * sizeof(unsigned char));
 +    cat_rast_row =  Rast_allocate_c_buf();
 +
++     
 +    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
 +    {
 +        scatts_conds = scatt_conds->cats_arr[i_cat];
@@ -4456,87 +4416,102 @@
 +        scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
 +        if(scatt_plts_cat_idx < 0)
 +            continue;
++        scatts_scatt_plts = scatts->cats_arr[scatt_plts_cat_idx];
 +
-+        scatt_plts_scatts = scatts->cats_arr[scatt_plts_cat_idx];
++        G_zero(belongs_pix, row_size * sizeof(unsigned short));
 +
-+        G_zero(belongs_pix, chunk_row_size * sizeof(unsigned short));
-+
++        /* if category has no conditions defined, scatter plots without any constraint are computed (default scatter plots) */
 +        if(!scatts_conds->n_a_scatts && !f_cats_rasts_conds[i_cat]) {
-+            for(i_scatt = 0; i_scatt < scatt_plts_scatts->n_a_scatts; i_scatt++)
++            for(i_scatt = 0; i_scatt < scatts_scatt_plts->n_a_scatts; i_scatt++)
 +            {       
-+                for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)                
-+                    belongs_pix[i_chunk_rows_pix] = 1;
++                /* all pixels belongs */
++                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)                
++                    belongs_pix[i_rows_pix] = 1;
 +            }
 +        }
++        /* compute belonging pixels for defined conditions */
 +        else
 +        {
 +            scatts_bands = scatts_conds->scatts_bands;
 +
-+            if(f_cats_rasts_conds[i_cat])
-+         
-+                fread(rast_pixs, sizeof(unsigned char), (chunk_row_size)/sizeof(unsigned char), f_cats_rasts_conds[i_cat]);
++            /* check conditions from category raster condtitions file */
++            if(f_cats_rasts_conds[i_cat]) {
++                n_pixs = fread(rast_pixs, sizeof(unsigned char), (row_size)/sizeof(unsigned char), f_cats_rasts_conds[i_cat]);
 +                if (ferror(f_cats_rasts_conds[i_cat]))
 +                {
 +                    G_free(rast_pixs);
 +                    G_free(belongs_pix);
-+                    G_message("Unable to read from file.");
++                    G_warning(_("Unable to read from category raster condtition file."));
 +                    return -1;
 +                }
-+                for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++                if (n_pixs != n_pixs) {
++                    G_free(rast_pixs);
++                    G_free(belongs_pix);
++                    G_warning(_("Invalid size of category raster conditions file."));
++                    return -1;
++
++                }
++
++                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
 +                {
-+                    if(rast_pixs[i_chunk_rows_pix] != 0 & 255)
-+                        belongs_pix[i_chunk_rows_pix] = 1;
++                    if(rast_pixs[i_rows_pix] != 0 & 255)
++                        belongs_pix[i_rows_pix] = 1;
 +                }
++            }
 +
-+            // test every defined conditions in scatter plots
++            /* check condtions defined in scatter plots*/
 +            for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
 +            {   
-+                b_1_chunk_rows =  chunk_rows[scatts_bands[i_scatt * 2]];
-+                b_2_chunk_rows =  chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++                b_1_rast_row = bands_rows[scatts_bands[i_scatt * 2]];
++                b_2_rast_row = bands_rows[scatts_bands[i_scatt * 2 + 1]];
 +
-+                band_1_null_chunk_rows =  null_chunk_rows[scatts_bands[i_scatt * 2]];
-+                band_2_null_chunk_rows =  null_chunk_rows[scatts_bands[i_scatt * 2 + 1]];
++                b_1_row = b_1_rast_row.row;
++                b_2_row = b_2_rast_row.row;
 +
-+                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
++                b_1_null_row =  b_1_rast_row.null_row;
++                b_2_null_row =  b_2_rast_row.null_row;
 +
-+                b_1_range = scatts_conds->scatts_arr[i_scatt]->band_1_range;
-+                b_2_range = scatts_conds->scatts_arr[i_scatt]->band_2_range;
++                b_1_range = b_1_rast_row.rast_range;
++                b_2_range = b_2_rast_row.rast_range;
 +
 +                b_1_range_size = b_1_range.max - b_1_range.min + 1;
-+
 +                max_arr_idx = (b_1_range.max -  b_1_range.min + 1) * (b_2_range.max -  b_2_range.min + 1);
-+                //G_message("max_arr_idx scatt_conds: %d", max_arr_idx);
 +
-+                for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
++                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
++
++                for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
 +                {
-+                    if(belongs_pix[i_chunk_rows_pix] || 
-+                       band_1_null_chunk_rows[i_chunk_rows_pix] == 1 || 
-+                       band_2_null_chunk_rows[i_chunk_rows_pix] == 1)
++                    /* pixels already belongs to category from category raster conditions file or contains null value in one of the bands */
++                    if(belongs_pix[i_rows_pix] || 
++                       b_1_null_row[i_rows_pix] == 1 || 
++                       b_2_null_row[i_rows_pix] == 1)
 +                        continue;
 +
-+                    array_idx = b_1_chunk_rows[i_chunk_rows_pix] - b_1_range.min + (b_2_chunk_rows[i_chunk_rows_pix] - b_2_range.min) * b_1_range_size;
-+                    /*TODO test value */
++                    array_idx = b_1_row[i_rows_pix] - b_1_range.min + (b_2_row[i_rows_pix] - b_2_range.min) * b_1_range_size;
 +                    if(array_idx < 0 || array_idx >= max_arr_idx) {
-+                        G_warning ("pixel out of range");
++                        G_warning ("Data inconsistent. Value computed for scatter plot is out of initialized range.");
 +                        continue;
 +                    }
++                    /* pixels meets condtion defined in scatter plot */
 +                    if(i_scatt_conds[array_idx])
-+                        belongs_pix[i_chunk_rows_pix] = 1;
++                        belongs_pix[i_rows_pix] = 1;
 +                }                
 +            }
 +        }
 +
++        /* update category raster with belonging pixels */
 +        if(fd_cats_rasts[i_cat] >= 0) {
 +            Rast_set_null_value(cat_rast_row, Rast_window_cols(), CELL_TYPE); 
 +
-+            for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
-+                if(belongs_pix[i_chunk_rows_pix])
-+                    cat_rast_row[i_chunk_rows_pix] = belongs_pix[i_chunk_rows_pix];
++            for(i_rows_pix = 0; i_rows_pix < row_size; i_rows_pix++)
++                if(belongs_pix[i_rows_pix])
++                    cat_rast_row[i_rows_pix] = belongs_pix[i_rows_pix];
 +
 +            Rast_put_c_row (fd_cats_rasts[i_cat], cat_rast_row); 
 +        }
 +
-+        update_cat_scatt_plts(chunk_rows, null_chunk_rows, chunk_row_size, belongs_pix, scatt_plts_scatts);
++        /* update scatter plots with belonging pixels */
++        update_cat_scatt_plts(bands_rows, belongs_pix, scatts_scatt_plts);
 +    }
 +
 +    G_free(cat_rast_row);
@@ -4570,18 +4545,18 @@
 +/*!
 +   \brief Helper function for clean up.
 +*/
-+static void free_compute_scatts_data(int * fd_bands, CELL ** chunk_rows, char ** null_chunk_rows, int * n_a_bands, int * bands_ids, 
++static void free_compute_scatts_data(int * fd_bands, struct rast_row * bands_rows, int n_a_bands, int * bands_ids, 
 +                                     int * fd_cats_rasts, FILE ** f_cats_rasts_conds, int n_a_cats)
 +{
 +    int i, band_id;
 +
-+    for(i = 0; i < (* n_a_bands); i++)
++    for(i = 0; i < n_a_bands; i++)
 +    {   
 +        band_id = bands_ids[i];
 +        if(band_id >= 0) {
 +            Rast_close(fd_bands[i]);
-+            G_free(chunk_rows[band_id]);
-+            G_free(null_chunk_rows[band_id]);
++            G_free(bands_rows[band_id].row);
++            G_free(bands_rows[band_id].null_row);
 +        }
 +    }
 +     
@@ -4598,133 +4573,107 @@
 +}
 +
 +/*!
-+   \brief Open pgm files.
-+*/
-+static int open_cats_rasts_files(const char ** cats_rasts, int n_a_cats, int * cats_ids, const char * mode, FILE ** fd_cats_rasts)
-+{
-+    int i_cat, id_cat;
++   \brief Compute scatter plots data.
 +
-+    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+    {
-+        id_cat = cats_ids[i_cat];
++    If category has not defined no category raster condition file and no scatter plot with consdtion,
++    default scatter plot is computed.
 +
-+        if(cats_rasts[id_cat]) {
-+            fd_cats_rasts[i_cat] = fopen(cats_rasts[id_cat], mode);
-+            if(!fd_cats_rasts[i_cat]) return -1;
-+        }
-+        else
-+            fd_cats_rasts[i_cat] = NULL;
-+    }
-+
-+    return 0;
-+}
-+
-+/*!
-+   \brief Write header for pgm file.
-+*/
-+static int cats_rasts_write_header(int n_a_cats, struct Cell_head * region, FILE ** fd_cats_rasts)
-+{
-+    int i_cat, id_cat, head_nchars;
-+    char cat_rast_header[1024];//TODO magic number 
-+
-+    head_nchars = get_cat_rast_header(region, cat_rast_header);
-+
-+    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+    {
-+        if(!fd_cats_rasts[i_cat])
-+            continue;
-+
-+        fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), fd_cats_rasts[i_cat]);
-+        if (ferror(fd_cats_rasts[i_cat])) return -1;
-+    }
-+
-+    return head_nchars;
-+
-+}
-+
-+/*!
-+   \brief Computes scatter plots data.
-+
-+   \param region analysis region, beaware that cats_rasts_conds must be generated for this region 
-+   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are selected areas (conditions) stored
-+   \param bands name of analyzed bands, order of bands id defined by their id 
++   \param region analysis region, beaware that all input data must be prepared for this region (bands (their ranges), cats_rasts_conds rasters...)
++   \param region function calls Rast_set_window for this region
++   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are stored selected areas (conditions) in scatter plots
++   \param cats_rasts_conds paths to category raster conditions files representing selected areas (conditions) in rasters for every category 
++   \param cats_rasts_conds index in array represents corresponding category id
++   \param cats_rasts_conds for manupulation with category raster conditions file see also I_id_scatt_to_bands() and I_insert_patch_to_cat_rast()
++   \param bands names of analyzed bands, order of bands is defined by their id
 +   \param n_bands number of bands
-+   \param cats_rasts_conds paths to pgm files for every category representing selected areas (conditions) from mapwindow 
-+   \param cats_rasts_conds location in the array is defined be category id
 +   \param [out] scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
-+   \param [out] cats_rasts array of raster maps names where will be stored all selected pixels for category
++   \param [out] cats_rasts array of raster maps names where will be stored all selected pixels for every category
++
++   \return  0 on success
++   \return -1 on failure
 +*/
-+int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** bands, 
-+                    int n_bands, const char ** cats_rasts_conds,  struct scCats * scatts, const char ** cats_rasts) 
++int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** cats_rasts_conds,
++                     const char ** bands, int n_bands, struct scCats * scatts, const char ** cats_rasts) 
 +{
-+    if (n_bands != scatts->n_bands ||
-+        n_bands != scatt_conds->n_bands)
-+        return -4;
-+
 +    const char *mapset;
 +    char header[1024];
 +
 +    int fd_cats_rasts[scatt_conds->n_a_cats];
 +    FILE * f_cats_rasts_conds[scatt_conds->n_a_cats];
 +
-+    CELL * chunk_rows[n_bands];
-+    char * null_chunk_rows[n_bands];
++    struct rast_row bands_rows[n_bands];
 +
 +    RASTER_MAP_TYPE data_type;
 +
-+    int nrows, i_band, id_band, n_a_bands, band_id, 
-+        chunk_row_size, i, i_row, head_nchars, i_cat, id_cat;
++    int nrows, i_band, n_a_bands, band_id, 
++        i, i_row, head_nchars, i_cat, id_cat;
++   
 +    int fd_bands[n_bands];
++    int bands_ids[n_bands];
++    int b_needed_bands[n_bands];  
++
++    Rast_set_window(region);
++
 +    for(i_band = 0; i_band < n_bands; i_band++)
 +        fd_bands[i_band] = -1;
 +    
-+    int bands_ids[n_bands];
 +    for(i_band = 0; i_band < n_bands; i_band++)
 +        bands_ids[i_band] = -1;
 +
-+    int b_needed_bands[n_bands];  
++    if (n_bands != scatts->n_bands ||
++        n_bands != scatt_conds->n_bands)
++        return -1;
++
 +    memset(b_needed_bands, 0, (size_t)n_bands * sizeof(int));
 +
 +    get_needed_bands(scatt_conds, &b_needed_bands[0]);
 +    get_needed_bands(scatts, &b_needed_bands[0]);
 +
-+    Rast_set_window(region);
++    n_a_bands = 0;
 +
-+    n_a_bands = 0;/*TODO realy needed?*/
-+    for(id_band = 0; id_band < n_bands; id_band++)
++    /* open band rasters, which are needed for computation */
++    for(band_id = 0; band_id < n_bands; band_id++)
 +    {
-+        if(b_needed_bands[id_band])
++        if(b_needed_bands[band_id])
 +        {
-+            G_debug(3, "Opening raster no. %d with name: %s", id_band, bands[id_band]);
++            G_debug(3, "Opening raster no. %d with name: %s", band_id, bands[band_id]);
 +
-+            /* TODO solve  returns*/
-+            if ((mapset = G_find_raster2(bands[id_band],"")) == NULL) {
-+                free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands, 
-+                                   &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+                return -4;
++            if ((mapset = G_find_raster2(bands[band_id],"")) == NULL) {
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
++                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++                G_warning(_("Unbale to read find raster <%s>"), bands[band_id]);
++                return -1;
 +            }
 +            
-+            if ((fd_bands[n_a_bands] = Rast_open_old(bands[id_band], mapset)) < 0) {
-+                free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands, 
-+                                   &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+                return -5;
++            if ((fd_bands[n_a_bands] = Rast_open_old(bands[band_id], mapset)) < 0) {
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
++                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++                G_warning(_("Unbale to open raster <%s>"), bands[band_id]);
++                return -1;
 +            }
 +
-+            //TODO check data type, minimum and maximum value
 +            data_type = Rast_get_map_type(fd_bands[n_a_bands]);
-+            //if(data_type != CELL)
-+            //    return -1;
++            if(data_type != CELL_TYPE) {
++                G_warning(_("Raster <%s> type is not <%s>"), bands[band_id], "CELL");
++                return -1;
++            }
 +
-+            //What happens if it is not CELL tyoe
-+            chunk_rows[id_band] =  Rast_allocate_c_buf();
-+            null_chunk_rows[id_band] =  Rast_allocate_null_buf();
++            bands_rows[band_id].row =  Rast_allocate_c_buf();
++            bands_rows[band_id].null_row =  Rast_allocate_null_buf();
 +
-+            bands_ids[n_a_bands] = id_band;
++            if(Rast_read_range(bands[band_id], mapset, &bands_rows[band_id].rast_range) != 1){
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, 
++                                         bands_ids, NULL, NULL, scatt_conds->n_a_cats);
++                G_warning(_("Unable to read range of raster <%s>"), bands[band_id]);
++                return -1;
++            }      
 +
++            bands_ids[n_a_bands] = band_id;
 +            ++n_a_bands;
 +        }
 +    }
 +
++    /* open category rasters condition files and category rasters */
 +    for(i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
 +    {
 +        id_cat = scatts->cats_ids[i_cat];
@@ -4733,42 +4682,49 @@
 +        }
 +        else
 +            fd_cats_rasts[i_cat] = -1;
-+    }
 +
-+    head_nchars =  get_cat_rast_header(region, header);
-+
-+    if (open_cats_rasts_files(cats_rasts_conds, scatt_conds->n_a_cats, scatt_conds->cats_ids, "rb", f_cats_rasts_conds) != 0) {
-+        free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands, 
-+                                 &bands_ids[0], &fd_cats_rasts[0], &f_cats_rasts_conds[0], scatt_conds->n_a_cats);
-+        return -2;
++        if(cats_rasts_conds[id_cat]) {
++            f_cats_rasts_conds[i_cat] = fopen(cats_rasts_conds[id_cat], "r");
++            if(!f_cats_rasts_conds[i_cat]) {
++                free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, 
++                                         f_cats_rasts_conds, f_cats_rasts_conds, scatt_conds->n_a_cats);
++                G_warning(_("Unable to open category raster condtition file <%s>"), bands[band_id]);
++                return -1;
++            }
++        }
++        else
++            f_cats_rasts_conds[i_cat] = NULL;
 +    }
 +
++    head_nchars =  get_cat_rast_header(region, header);
 +    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
 +        if(f_cats_rasts_conds[i_cat])
-+            fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET);
++            if( fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET) != 0) {
++                G_warning(_("Corrupted category raster conditions file (fseek failed)"));
++                return -1;
++            }
 +
 +    nrows = Rast_window_rows();
-+    chunk_row_size = Rast_window_cols();
 +
++    /* analyze bands by rows */
 +    for (i_row = 0; i_row < nrows; i_row++)
 +    {
 +        for(i_band = 0; i_band < n_a_bands; i_band++)
 +        {   
 +            band_id = bands_ids[i_band];
-+            G_debug(3, "Reading data for band %d", band_id);
-+            Rast_get_c_row(fd_bands[i_band], chunk_rows[band_id], i_row);
-+            Rast_get_null_value_row (fd_bands[i_band], null_chunk_rows[band_id], i_row);
++            Rast_get_c_row(fd_bands[i_band], bands_rows[band_id].row, i_row);
++            Rast_get_null_value_row (fd_bands[i_band], bands_rows[band_id].null_row, i_row);
 +        }
-+        if(compute_scatts_from_chunk_row(scatts, scatt_conds, chunk_rows, null_chunk_rows, chunk_row_size,  &f_cats_rasts_conds[0], &fd_cats_rasts[0], region) == -1) 
++        if(compute_scatts_from_chunk_row(region, scatt_conds, f_cats_rasts_conds, bands_rows, scatts, fd_cats_rasts) == -1) 
 +        {
-+            free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands, 
-+                               &bands_ids[0], &fd_cats_rasts[0], &f_cats_rasts_conds[0], scatt_conds->n_a_cats);
-+            return -3;
++            free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, fd_cats_rasts, 
++                                     f_cats_rasts_conds, scatt_conds->n_a_cats);
++            return -1;
 +        }
 + 
 +    }
-+    free_compute_scatts_data(&fd_bands[0], &chunk_rows[0], &null_chunk_rows[0], &n_a_bands, 
-+                             &bands_ids[0], &fd_cats_rasts[0], &f_cats_rasts_conds[0], scatt_conds->n_a_cats); 
++    free_compute_scatts_data(fd_bands, bands_rows, n_a_bands, bands_ids, 
++                             fd_cats_rasts, f_cats_rasts_conds, scatt_conds->n_a_cats); 
 +    return 0;    
 +}
 \ No newline at end of file



More information about the grass-commit mailing list