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

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Aug 10 00:20:08 PDT 2013


Author: turek
Date: 2013-08-10 00:20:08 -0700 (Sat, 10 Aug 2013)
New Revision: 57440

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
scatter plot: new layout and other changes and fixes

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-08-09 08:26:52 UTC (rev 57439)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-08-10 07:20:08 UTC (rev 57440)
@@ -1,114 +1,35 @@
-Index: vector/v.edit/main.c
+Index: include/defs/vedit.h
 ===================================================================
---- vector/v.edit/main.c	(revision 57336)
-+++ vector/v.edit/main.c	(working copy)
-@@ -299,7 +299,7 @@
- 	move_z = atof(params.move->answers[2]);
- 	G_verbose_message(_("Threshold value for snapping is %.2f"),
- 			  thresh[THRESH_SNAP]);
--	ret = Vedit_move_lines(&Map, BgMap, nbgmaps, List, move_x, move_y, move_z, snap, thresh[THRESH_SNAP]);
-+	ret = Vedit_move_lines(&Map, BgMap, nbgmaps, List, move_x, move_y, move_z, snap, thresh[THRESH_SNAP], NULL);
- 	G_message(_("%d features moved"), ret);
- 	break;
-     case MODE_VERTEX_MOVE:
-@@ -308,15 +308,15 @@
- 	move_z = atof(params.move->answers[2]);
- 	G_verbose_message(_("Threshold value for snapping is %.2f"),
- 			  thresh[THRESH_SNAP]);
--	ret = Vedit_move_vertex(&Map, BgMap, nbgmaps, List, coord, thresh[THRESH_COORDS], thresh[THRESH_SNAP], move_x, move_y, move_z, move_first, snap);
-+	ret = Vedit_move_vertex(&Map, BgMap, nbgmaps, List, coord, thresh[THRESH_COORDS], thresh[THRESH_SNAP], move_x, move_y, move_z, move_first, snap, NULL);
- 	G_message(_("%d vertices moved"), ret);
- 	break;
-     case MODE_VERTEX_ADD:
--	ret = Vedit_add_vertex(&Map, List, coord, thresh[THRESH_COORDS]);
-+	ret = Vedit_add_vertex(&Map, List, coord, thresh[THRESH_COORDS], NULL);
- 	G_message(_("%d vertices added"), ret);
- 	break;
-     case MODE_VERTEX_DELETE:
--	ret = Vedit_remove_vertex(&Map, List, coord, thresh[THRESH_COORDS]);
-+	ret = Vedit_remove_vertex(&Map, List, coord, thresh[THRESH_COORDS], NULL);
- 	G_message(_("%d vertices removed"), ret);
- 	break;
-     case MODE_BREAK:
-Index: include/imagery.h
-===================================================================
---- include/imagery.h	(revision 57336)
-+++ include/imagery.h	(working copy)
-@@ -135,6 +135,48 @@
-     
- } IClass_statistics;
+--- include/defs/vedit.h	(revision 57437)
++++ include/defs/vedit.h	(working copy)
+@@ -33,6 +33,8 @@
+ int Vedit_merge_lines(struct Map_info *, struct ilist *);
  
-+/* Scatter Plot backend */
-+struct scCats 
-+{
-+    int type; //TODO do not identify it with number
-+
-+    int n_cats;
-+    
-+    int n_bands;
-+    int n_scatts;
-+
-+    int   n_a_cats;
-+    int * cats_ids;
-+    int * cats_idxs;
-+
-+    struct scScatts ** cats_arr;
-+};
-+
-+struct scScatts
-+{
-+    int n_a_scatts;
-+    
-+    int * scatts_bands;
-+    int * scatt_idxs;
-+
-+    struct scdScattData ** scatts_arr;
-+};
-+
-+#define SC_SCATT_DATA          0 
-+#define SC_SCATT_CONDITIONS    1
-+
-+struct scdScattData
-+{
-+    int n_vals; //TODO delete???
-+    
-+    struct Range band_1_range;
-+    struct Range band_2_range;
-+
-+
-+    unsigned char  * b_conds_arr;
-+    unsigned int  * scatt_vals_arr;
-+};
-+
- #define SIGNATURE_TYPE_MIXED 1
+ /* move.c */
++int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
++		     		 struct ilist *, double, double, double, int, double);
+ int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
+ 		     struct ilist *, double, double, double, int, double);
  
- #define GROUPFILE "CURGROUP"
 Index: include/defs/imagery.h
 ===================================================================
---- include/defs/imagery.h	(revision 57336)
+--- include/defs/imagery.h	(revision 57437)
 +++ include/defs/imagery.h	(working copy)
-@@ -110,6 +110,29 @@
+@@ -110,6 +110,22 @@
  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 *);
-+void I_sc_get_active_categories(int *, int *, struct scCats *);
 +int I_sc_add_cat(struct scCats *, int);
-+int I_sc_delete_cat(struct scCats *, int);
 +int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
-+int I_sc_remove_scatt_data(struct scCats *, struct scdScattData *, int, int);
-+int I_sc_set_value(struct scCats *, int, int, 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_get_range_min_max(struct scdScattData *, CELL *, CELL *, CELL *, CELL *);
-+void * I_scd_get_data_ptr(struct scdScattData *);
-+int I_scd_set_value(struct scdScattData *, unsigned int, unsigned int);
 +
 +int I_compute_scatts(struct Cell_head *, struct scCats *, const char **, 
-+                     int, struct scCats *, const char **,  const char **);
++                     int, const char **, 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 *);
@@ -117,1264 +38,410 @@
  /* sig.c */
  int I_init_signatures(struct Signature *, int);
  int I_new_signature(struct Signature *);
-Index: include/defs/vedit.h
+Index: include/imagery.h
 ===================================================================
---- include/defs/vedit.h	(revision 57336)
-+++ include/defs/vedit.h	(working copy)
-@@ -34,7 +34,7 @@
+--- include/imagery.h	(revision 57437)
++++ include/imagery.h	(working copy)
+@@ -135,6 +135,59 @@
+     
+ } IClass_statistics;
  
- /* move.c */
- int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
--		     struct ilist *, double, double, double, int, double);
-+		     struct ilist *, double, double, double, int, double, struct ilist *);
- 
- /* render.c */
- struct robject_list *Vedit_render_map(struct Map_info *, struct bound_box *, int,
-@@ -56,11 +56,11 @@
- int Vedit_move_vertex(struct Map_info *, struct Map_info **, int,
- 		      struct ilist *,
- 		      struct line_pnts *, double, double,
--		      double, double, double, int, int);
-+		      double, double, double, int, int, struct ilist *);
- int Vedit_add_vertex(struct Map_info *Map, struct ilist *,
--		     struct line_pnts *, double);
-+		     struct line_pnts *, double, struct ilist *);
- int Vedit_remove_vertex(struct Map_info *, struct ilist *,
--			struct line_pnts *, double);
-+			struct line_pnts *, double, struct ilist *);
- 
- /* zbulk.c */
- int Vedit_bulk_labeling(struct Map_info *, struct ilist *,
-Index: gui/wxpython/scatt_plot/controllers.py
-===================================================================
---- gui/wxpython/scatt_plot/controllers.py	(revision 0)
-+++ gui/wxpython/scatt_plot/controllers.py	(working copy)
-@@ -0,0 +1,518 @@
-+"""!
-+ at package scatt_plot.controllers
++/* Scatter Plot backend */
 +
-+ at brief Controller layer for scatter plot tool.
++#define SC_SCATT_DATA          0 
++#define SC_SCATT_CONDITIONS    1
 +
-+Classes:
 +
-+(C) 2013 by the GRASS Development Team
++/*! Holds list of all catagories. 
++    It can contain selected areas for scatter plots (SC_SCATT_CONDITIONS type) or computed scatter plots (SC_SCATT_DATA type).
++*/
++struct scCats 
++{
++    int type;  /*!< SC_SCATT_DATA -> computed scatter plots, SC_SCATT_CONDITIONS -> set conditions for scatter plots*/
 +
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
++    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 */
 +
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
++    int   n_a_cats; /*!< number of used categories */
++    int * cats_ids; /*!< category id */
++    int * cats_idxs; /*!< internal category idx (idx in cats_arr)*/
 +
-+#TODO
-+import wx
++    struct scScatts ** cats_arr; /*!< array of pointers to struct scScatts */
++};
 +
-+from core.gcmd     import GException, GError, RunCommand
 +
-+from scatt_plot.sc_pl_core import Core, idBandsToidScatt
++/*! Holds list of all scatter plots, which belongs to category. 
++*/
++struct scScatts
++{
++    int n_a_scatts; /*!< number of used 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)*/
 +
-+from scatt_plot.gthreading import gThread
-+from core.gconsole         import EVT_CMD_DONE
++    struct scdScattData ** scatts_arr; /*!< array of pointers to scdScattData */
++};
 +
-+from grass.pydispatch.signal import Signal
++/*! Holds scatter plot data.
++*/
++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) */
 +
-+class ScattsManager(wx.EvtHandler):
-+    def __init__(self, guiparent, giface, iclass_mapwin):
-+        #TODO remove iclass parameter
 +
-+        wx.EvtHandler.__init__(self)
-+        self.giface = giface
-+        self.mapDisp  = giface.GetMapDisplay()
-+        self.mapWin = giface.GetMapWindow()
++    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) */
++};
 +
-+        if iclass_mapwin:
-+            self.mapWin = iclass_mapwin
-+
-+        self.guiparent = guiparent
-+
-+        self.core = Core()
-+        self.scatts_dt = self.core.GetScattsData()
-+
-+        self.cats_mgr = CategoriesManager(self, self.core)
-+
-+        self.thread = gThread(self);
-+        
-+        self.scatt_plts = {}
-+        self.added_cats_rasts = {}
-+
-+        self.cats_to_update = []
-+
-+        self.edit_cat_type =  None
-+
-+        self.data_set = False
-+
-+        if iclass_mapwin: 
-+            self.mapWin_conn = MapWinConnection(self, self.mapWin, self.core.CatRastUpdater())
-+            self.iclass_conn = IClassConnection(self, iclass_mapwin.parent, self.cats_mgr)
+ #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:
-+            self.mapWin_conn = None
-+            self.iclass_conn = None
++            cat = None
 +
-+        self.tasks_pids = {
-+                            'add_scatt' : [],
-+                            'set_data' : -1,
-+                            'set_edit_cat_data' : -1,
-+                            'mapwin_conn' : [],
-+                            'render_plots' : -1
-+                           }
+         if toolbar.choice.IsEmpty():
+             toolbar.EnableControls(False)
+         else:
+             toolbar.EnableControls(True)
 +
-+        self.Bind(EVT_CMD_DONE, self.OnThreadDone)
++        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
 +
-+    def SetData(self, bands):
-+        self.data_set = False
-+        self.tasks_pids['set_data'] = self.thread.GetId()
-+        self.thread.Run(callable = self.core.SetData, bands = bands)
+ class IClassMapFrame(DoubleMapFrame):
+     """! wxIClass main frame
+     
+@@ -115,6 +117,10 @@
+             lambda:
+             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
+         self.SetSize(size)
 +
-+        #for i in range(1):
-+        #    self.AddScattPlot(i)
++        self.groupSet = Signal("IClassMapFrame.groupSet")
++        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
 +
-+    def SetDataDone(self, event):
-+        self.data_set = True
-+        self.cats_mgr.InitCoreCats()
-+
-+    def OnOutput(self, event):
-+        """!Print thread output according to debug level.
+         #
+         # 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
 +        """
-+        print event.text
-+
-+    def GetBands(self):
-+        return self.core.GetBands()
-+
-+    def AddScattPlot(self, scatt_id):
-+
-+        self.tasks_pids['add_scatt'].append(self.thread.GetId())
-+        self.thread.Run(callable = self.core.AddScattPlot, scatt_id = scatt_id)
-+
-+    def RenderScattPlts(self):
-+
-+        cats_attrs = self.cats_mgr.GetCategoriesAttrs()
-+        for scatt_id, scatt in self.scatt_plts.iteritems():
-+            scatt_dt = self.scatts_dt.GetScatt(scatt_id)
-+            scatt.Plot(scatt_dt, cats_attrs)
-+
-+
-+    def AddScattPlotDone(self, event):
-+        
-+        scatt_id = event.kwds['scatt_id']
-+
-+        #TODO guiparent - not very good
-+        self.scatt_plts[scatt_id] = self.guiparent.NewScatterPlot(scatt_id = scatt_id)
-+
-+        if self.edit_cat_type:
-+            self.scatt_plts[scatt_id].StartCategoryEdit()
-+
-+        scatt_dt = self.scatts_dt.GetScatt(scatt_id)
-+        
-+        cats_attrs = self.cats_mgr.GetCategoriesAttrs()
-+
-+        self.scatt_plts[scatt_id].Plot(scatt_dt, cats_attrs)
-+        #for scatt in scatt_dt.itervalues():
-+        #    del scatt 
-+        self.scatt_plts[scatt_id].GetParent().Show()
-+        print "ok %d" % scatt_id
-+
-+    def CleanUp(self):
-+        self.core.CleanUp()
-+
-+        for scatt_id, scatt in self.scatt_plts.items():
-+            scatt.CleanUp()
-+            del self.scatt_plts[scatt_id]
-+
-+    def OnThreadDone(self, event):
-+        
-+        if event.exception:
-+            GError(str(event.exception))
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
 +            return
 +
-+        if event.pid in self.tasks_pids['mapwin_conn']:
-+            self.tasks_pids['mapwin_conn'].remove(event.pid)
-+            updated_cats = event.ret
++        try:
++          from scatt_plot.dialogs import ScattPlotMainDialog
++          self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
 +
-+            for cat in updated_cats:
-+                if cat not in  self.cats_to_update:
-+                    self.cats_to_update.append(cat)
++          scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
++          scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().digit)
 +
-+            if not self.tasks_pids['mapwin_conn']:
-+                self.tasks_pids['render_plots'] = self.thread.GetId()
-+                self.thread.Run(callable = self.core.ComputeCatScatts, 
-+                                cats_ids = self.cats_to_update[:])
-+                del self.cats_to_update[:]
-+ 
-+            return
++          self.dialogs['scatt_plot'].CenterOnScreen()
++          self.dialogs['scatt_plot'].Show()
 +
-+        if self.tasks_pids['render_plots'] == event.pid:
-+            #TODO how to put it to the thread - kils gui
-+            self.RenderScattPlts()
-+            return
-+            
-+        if event.pid in self.tasks_pids['add_scatt']:
-+            self.AddScattPlotDone(event)
-+            return
++        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
 +
-+        if self.tasks_pids['set_data'] == event.pid:
-+            self.SetDataDone(event)
-+            return
-+        
-+        if self.tasks_pids['set_edit_cat_data'] == event.pid:
-+            self.SetEditCatDataDone(event)
-+            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)
 +
-+    def EditCat(self, edit_type):
-+
-+        self.edit_cat_type = edit_type
-+
-+        if self.edit_cat_type:
-+            for scatt in self.scatt_plts.itervalues():
-+                scatt.StopCategoryEdit()
-+                scatt.StartCategoryEdit()
-+
-+        else:
-+            for scatt in self.scatt_plts.itervalues():
-+                scatt.StopCategoryEdit()
-+
-+    def SetEditCatData(self, scatt_id, bbox):
-+        
-+        value = 1
-+        if self.edit_cat_type == 'remove':
-+            value = 0
-+
-+        self.tasks_pids['set_edit_cat_data'] = self.thread.GetId()
-+
-+        sel_cat_id = self.cats_mgr.GetSelectedCat()
-+        
-+        self.thread.Run(callable = self.core.SetEditCatData, 
-+                        scatt_id = scatt_id,
-+                        cat_id = sel_cat_id,
-+                        bbox = bbox,
-+                        value = value)
-+    
-+    def SetEditCatDataDone(self, event):
-+
-+        self.RenderScattPlts()
-+
-+        cat_id = event.kwds["cat_id"]
-+
-+        cat_rast = self.core.GetCatRastOut(cat_id)
-+
-+
-+        if cat_rast not in self.added_cats_rasts.values():
-+
-+            cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
-+
-+            #TODO use standard raster lib
-+            name = "cat_%d" % cat_id
-+            ret, err_msg = RunCommand('r.external',
-+                                      output = name,
-+                                      getErrorMsg = True,
-+                                      input = cat_rast,
-+                                      flags = "o",
-+                                      overwrite = True)
-+
-+            if ret != 0:
-+                GError(_("r.external failed\n%s" % err_msg))
-+
-+            region = self.core.GetRegion()
-+            ret, err_msg = RunCommand('r.region',
-+                                      map = name,
-+                                      getErrorMsg = True,
-+                                      n = "%f" % region['n'],
-+                                      s = "%f" % region['s'],
-+                                      e = "%f" % region['e'],
-+                                      w = "%f" % region['w'],
-+                                      )
-+
-+            region = self.core.GetRegion()
-+            ret, err_msg = RunCommand('r.colors',
-+                                      map = name,
-+                                      rules = "-",
-+                                      stdin = "1 %s" % cats_attrs["color"],
-+                                      getErrorMsg = True)
-+
-+            if ret != 0:
-+                GError(_("r.region failed\n%s" % err_msg))
-+
-+            self.mapWin.Map.AddLayer(ltype = "raster", name =  "cat_%d" % cat_id, render = True,
-+                                     command = ["d.rast", "map=%s" % name, "values=1"])                
-+
-+            #elif self.giface.GetLayerTree():
-+            #    self.giface.GetLayerTree().AddLayer("raster", lname =  "cat_%d" % cat_id, lchecked = True,
-+            #                    lcmd = ["d.rast", "map=%s" % name, "values=1"])
-+
-+            if ret != 0:
-+                GError(_("r.region failed\n%s" % err_msg))
-+
-+            self.added_cats_rasts[cat_id] = cat_rast
-+
-+        self.giface.updateMap.emit()
-+
-+    def DigitDataChanged(self, vectMap, digit):
-+        
-+        if self.mapWin_conn:
-+            self.mapWin_conn.DigitDataChanged(vectMap, digit)
-+            return 1
-+        else:
-+            return 0
-+
-+    def GetCategoriesManager(self):
-+        return self.cats_mgr
-+
-+class CategoriesManager:
-+
-+    def __init__(self, scatt_mgr, core):
-+
-+        self.core = core
-+        self.scatt_mgr = scatt_mgr
-+
-+        self.cats = {}
-+        self.cats_ids = []
-+
-+        self.sel_cat_id = -1
-+
-+        self.initialized = Signal('CategoriesManager.initialized')
-+        self.setCategoryAttrs = Signal('CategoriesManager.setCategoryAttrs')
-+        self.deletedCategory = Signal('CategoriesManager.deletedCategory')
-+        self.addedCategory = Signal('CategoriesManager.addedCategory')
-+
-+    def Clear(self):
-+
-+        self.cats.clear()
-+        del self.cats_ids[:]
-+
-+        self.sel_cat_id = -1   
-+
-+    def InitCoreCats(self):
-+        if self.scatt_mgr.data_set:
-+            for cat_id in self.cats_ids:
-+                self.core.AddCategory(cat_id)
-+
-+    def AddCategory(self, cat_id = None, name = None, color = None):
-+
-+        if cat_id is None:
-+            if self.cats_ids:
-+                cat_id = max(self.cats_ids) + 1
-+            else:
-+                cat_id = 1
-+
-+        if self.scatt_mgr.data_set:
-+            ret = self.core.AddCategory(cat_id)
-+            if ret < 0: #TODO
-+                return -1;
-+
-+        self.cats[cat_id] = {
-+                                'name' : _('Category %s' % cat_id ),
-+                                'color' : "0:0:0"
-+                            }
-+        self.cats_ids.append(cat_id)
-+
-+        if name is not None:
-+            self.cats[cat_id]["name"] = name
-+   
-+        if color is not None:
-+            self.cats[cat_id]["color"] = color
-+
-+        self.addedCategory.emit(cat_id = cat_id,
-+                                name = self.cats[cat_id]["name"], 
-+                                color = self.cats[cat_id]["color"] )
-+        return cat_id
-+
-+    def SetCategoryAttrs(self, cat_id, attrs_dict):
-+        for k, v in attrs_dict.iteritems():
-+            self.cats[cat_id][k] = v
-+
-+        self.setCategoryAttrs.emit(cat_id = cat_id, attrs_dict = attrs_dict)
-+
-+    def DeleteCategory(self, cat_id):
-+
-+        if self.scatt_mgr.data_set:
-+            self.core.DeleteCategory(cat_id)
-+        del self.cats[cat_id]
-+        self.cats_ids.remove(cat_id)
-+
-+        self.deletedCategory.emit(cat_id = cat_id)
-+
-+    #TODO emit event?
-+    def SetSelectedCat(self, cat_id):
-+        self.sel_cat_id = cat_id
-+
-+    def GetSelectedCat(self):
-+        return self.sel_cat_id
-+
-+    def GetCategoryAttrs(self, cat_id):
-+        #TODO is mutable
-+        return self.cats[cat_id]
-+
-+    def GetCategoriesAttrs(self):
-+        #TODO is mutable
-+        return self.cats
-+     
-+    def GetCategories(self):
-+        return self.cats_ids[:]
-+
-+class MapWinConnection:
-+    def __init__(self, scatt_mgr, mapWin, scatt_rast_updater):
-+        self.mapWin = mapWin
-+        self.vectMap = None
-+        self.scatt_rast_updater = scatt_rast_updater
-+        self.scatt_mgr = scatt_mgr
-+        self.cats_mgr = scatt_mgr.cats_mgr
-+
-+        self.thread = self.scatt_mgr.thread
-+
-+        #TODO
-+        self.mapWin.parent.toolbars["vdigit"].editingStarted.connect(self.DigitDataChanged)
-+
-+        #def ChangeMap(self, vectMap, layers_cats):
-+        #     self.vectMap = vectMap
-+        #     self.layers_cats = layers_cats
-+
-+        #ret, region, msg = RunCommand("v.to.rast",
-+        #                              flags = "gp",
-+        #                              getErrorMsg = True,
-+        #                              read = True)
-+
-+    def _connectSignals(self):
-+        self.digit.featureAdded.connect(self.AddFeature)
-+        self.digit.areasDeleted.connect(self.DeleteAreas)
-+        self.digit.featuresDeleted.connect(self.DeleteAreas)
-+        self.digit.vertexMoved.connect(self.ChangeVertex)
-+        self.digit.vertexRemoved.connect(self.ChangeVertex)
-+        self.digit.lineEdited.connect(self.ChangeVertex)
-+        self.digit.featuresMoved.connect(self.MoveFeatures)
-+
-+    def AddFeature(self, new_geom, cat):
-+        if not self.scatt_mgr.data_set:
-+            return
-+
-+        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+        self.thread.Run(callable = self.scatt_rast_updater.AddedFeature, 
-+                        new_geom = new_geom, 
-+                        cat = cat)
-+
-+    def DeleteAreas(self, old_geoms, old_areas_cats):
-+        if not self.scatt_mgr.data_set:
-+            return
-+
-+        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+        self.thread.Run(callable = self.scatt_rast_updater.DeletedAreas, 
-+                        old_geoms = old_geoms, 
-+                        old_areas_cats = old_areas_cats)
-+
-+    def ChangeVertex(self, new_geom, new_areas_cats, old_geom, old_areas_cats):
-+        if not self.scatt_mgr.data_set:
-+            return
-+
-+        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+        self.thread.Run(callable = self.scatt_rast_updater.ChangedVertex, 
-+                        new_geom = new_geom, 
-+                        old_geom = old_geom, 
-+                        old_areas_cats = old_areas_cats,
-+                        new_areas_cats = new_areas_cats)
-+
-+    def MoveFeatures(self, old_geoms, old_areas_cats, new_areas_cats, move):
-+        if not self.scatt_mgr.data_set:
-+            return
-+
-+        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
-+        self.thread.Run(callable = self.scatt_rast_updater.MovedFeatures, 
-+                        move = move, 
-+                        old_geoms = old_geoms, 
-+                        old_areas_cats = old_areas_cats,
-+                        new_areas_cats = new_areas_cats)
-+
-+    def DigitDataChanged(self, vectMap, digit):
-+
-+        self.digit = digit
-+        self.vectMap = vectMap
-+
-+        self.scatt_rast_updater.SetVectMap(vectMap)
-+
-+        self._connectSignals()
-+
-+class IClassConnection:
-+    def __init__(self, scatt_mgr, iclass_frame, cats_mgr):
-+        self.iclass_frame = iclass_frame
-+        self.stats_data   = self.iclass_frame.stats_data
-+        self.cats_mgr     = cats_mgr
-+        self.scatt_mgr    = scatt_mgr
-+
-+        self.stats_data.statisticsAdded.connect(self.AddCategory)
-+        self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
-+        self.stats_data.allStatisticsDeleted.connect(self.DeletAllCategories)
-+        self.stats_data.statisticsSet.connect(self.SetCategory)
-+
-+        self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
-+        self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
-+        self.cats_mgr.addedCategory.connect(self.AddStatistics)
-+
-+        self.SyncCats()
-+
-+    def SyncCats(self):
-+        self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
-+        cats = self.stats_data.GetCategories()
-+        for c in cats:
-+            stats = self.stats_data.GetStatistics(c)
-+            self.cats_mgr.AddCategory(c, stats.name, stats.color)
-+        self.cats_mgr.addedCategory.connect(self.AddStatistics)
-+
-+    def AddCategory(self, cat, name, color):
-+        self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
-+        self.cats_mgr.AddCategory(cat_id = cat, name = name, color = color)
-+        self.cats_mgr.addedCategory.connect(self.AddStatistics)
-+
-+    def DeleteCategory(self, cat):
-+        self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
-+        self.cats_mgr.DeleteCategory(cat)
-+        self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
-+
-+
-+    def DeletAllCategories(self):
-+
-+        self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
-+        cats = self.stats_data.GetCategories()
-+        for c in cats:
-+            self.cats_mgr.DeleteCategory(c)
-+        self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
-+
-+    def SetCategory(self, cat, stats):
-+
-+        self.cats_mgr.setCategoryAttrs.disconnect(self.SetStatistics)
-+        cats_attr = {}
-+        for attr in ['name', 'color']:
-+            if stats.has_key(attr):
-+                cats_attr[attr] = stats[attr]
-+
-+        if cats_attr:
-+            self.cats_mgr.SetCategoryAttrs(cat, cats_attr)
-+        self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
-+
-+
-+    def SetStatistics(self, cat_id, attrs_dict):
-+        self.stats_data.statisticsSet.disconnect(self.SetCategory)
-+        self.stats_data.GetStatistics(cat_id).SetStatistics(attrs_dict)
-+        self.stats_data.statisticsSet.connect(self.SetCategory)
-+
-+    def AddStatistics(self, cat_id, name, color):
-+        self.stats_data.statisticsAdded.disconnect(self.AddCategory)
-+        self.stats_data.AddStatistics(cat_id, name, color)
-+        self.stats_data.statisticsAdded.connect(self.AddCategory)
-+
-+    def DeleteStatistics(self, cat_id):
-+        self.stats_data.statisticsDeleted.disconnect(self.DeleteCategory)
-+        self.stats_data.DeleteStatistics(cat_id)
-+        self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
-Index: gui/wxpython/scatt_plot/sc_pl_core.py
++        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/scatt_plot/sc_pl_core.py	(revision 0)
-+++ gui/wxpython/scatt_plot/sc_pl_core.py	(working copy)
-@@ -0,0 +1,697 @@
-+"""!
-+ at package scatt_plot.scatt_plot
+--- 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
 +
-+ at brief Non GUI functions.
+         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+-        
 +
-+Classes:
+         self._createControlPanel()
+-        
++        self._createPlotPanel()
++        self._createScatterPlotPanel()
 +
-+(C) 2013 by the GRASS Development Team
+         self.SetSizer(self.mainSizer)
+         self.mainSizer.Fit(self)
+         self.Layout()
+         
++    def _createPlotPanel(self):
 +
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
++        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)
 +
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+#TODO
-+import time
-+
-+import numpy as np
-+
-+from math import sqrt, ceil, floor
-+from copy import deepcopy
-+
-+from grass.script   import core as grass
-+from core.gcmd      import GException, GError, RunCommand
-+
-+import grass.script as grass
-+
-+from core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
-+                   SC_SCATT_DATA, SC_SCATT_CONDITIONS
-+
-+class Core:
-+    def __init__(self):
-+        
-+        self.an_data = AnalyzedData()
-+
-+        self.scatts_dt = ScattPlotsData(self.an_data)
-+        self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
-+
-+        self.cat_rast_updater = CatRastUpdater(self.scatts_dt, self.an_data, self)
-+
-+    def SetData(self, bands):
-+        self.an_data.Create(bands)
-+
-+        n_bands = len(self.GetBands())
-+
-+        self.scatts_dt.Create(n_bands)
-+        self.scatt_conds_dt.Create(n_bands)
-+
-+    def AddCategory(self, cat_id):
-+        self.scatts_dt.AddCategory(cat_id)
-+        return self.scatt_conds_dt.AddCategory(cat_id)
-+
-+    def DeleteCategory(self, cat_id):
-+        self.scatts_dt.DeleteCategory(cat_id)
-+        self.scatt_conds_dt.DeleteCategory(cat_id)
-+
-+    def CleanUp(self):
-+        self.scatts_dt.CleanUp()
-+        self.scatt_conds_dt.CleanUp()
-+
-+    def GetBands(self):
-+        return self.an_data.GetBands()
-+
-+    def GetScattsData(self):
-+        return self.scatts_dt;
-+
-+    def GetRegion(self):
-+        return self.an_data.GetRegion()
-+
-+    def GetCatRastOut(self, cat_id):
-+        return self.scatts_dt.GetCatRastOut(cat_id)
-+
-+    def AddScattPlot(self, scatt_id):
+     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)
+-        
 +    
-+        self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++    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
 +
-+        scatt_conds = self.scatt_conds_dt.GetData({0 : []})
-+        scatts = self.scatts_dt.GetData({0 : [scatt_id]})
+     def OnPlotTypeSelected(self, event):
+         """!Plot type selected"""
 +
-+        bands = self.an_data.GetBands()
-+        cats_rasts_out = self.scatts_dt.GetCatsRastsOut()
-+        cats_rasts_in = self.scatts_dt.GetCatsRastsIn()
++        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()
 +
-+        #for cat in scatts.itervalues():
-+        #    for scatt_id in cat.itervalues():
-+        #        print cat
-+        #        scatt_id.values()[0].flush()
-+        #        del scatt_id
+         if self.currentCat is None:
+             return
+-        
 +
-+        returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands, 
-+                                           len(self.GetBands()), scatts, cats_rasts_in, cats_rasts_out)
-+        #self.scatts_dt.SetData(scatts)
+         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()
+-            
 +
-+    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++        self.Layout()
 +
-+        if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
-+            return False
 +
-+        arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
+     def StddevChanged(self):
+         """!Standard deviation multiplier changed, redraw histograms"""
+         if self.plotSwitch.GetSelection() == 0:
+@@ -89,7 +128,7 @@
+             panel.Destroy()
+             
+         self.canvasList = []
+-            
 +
-+        for k, v in bbox.iteritems():
-+            bbox[k] = self._validExtend(v)
-+
-+        arr[bbox['btm_y'] : bbox['up_y'], bbox['btm_x'] : bbox['up_x']] = value
-+        arr.flush()
-+        #del arr
-+
-+        start_time = time.clock()
-+        self.ComputeCatScatts([cat_id])
-+        print "time"
-+        print time.clock() - start_time
-+        return True
-+
-+    def ComputeCatScatts(self, cats_ids):
-+
-+        requested_dt = {}
-+        requested_dt_conds = {}
-+
-+        for c in cats_ids:
-+            requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
-+            requested_dt[c] = self.scatts_dt.GetCatScatts(c)
-+
-+        scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
-+        scatts = self.scatts_dt.GetData(requested_dt)
-+
-+        bands = self.an_data.GetBands()
-+
-+        cats_rasts_out = self.scatts_dt.GetCatsRastsOut()
-+        cats_rasts_in = self.scatts_dt.GetCatsRastsIn()
-+
-+        returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
-+                                           len(self.GetBands()), scatts, cats_rasts_in, cats_rasts_out)
+     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.scatts_dt.SetData(scatts)
-+
-+    def CatRastUpdater(self):
-+        return self.cat_rast_updater
-+        
-+    def _validExtend(self, val):
-+        #TODO do it general
-+        if  val > 255:
-+            val = 255
-+        elif val < 0:
-+            val = 0
-+
-+        return val
-+
-+class CatRastUpdater:
-+
-+    def __init__(self, scatts_dt, an_data, core):
-+        self.scatts_dt = scatts_dt
-+        self.an_data = an_data # TODO may be confusing
-+        self.core = core
-+        self.vectMap = None
-+
-+    def _getBbox(self, points):
-+        bbox = { "maxx" : None,
-+                 "maxy" : None,
-+                 "minx" : None,
-+                 "miny" : None,
-+                }
-+           
-+        for pt in points:       
-+            if not bbox['maxy']:
-+                bbox['maxy'] = pt[1]
-+                bbox['miny'] = pt[1]
-+                bbox['maxx'] = pt[0]
-+                bbox['minx'] = pt[0]
-+                continue
-+                
-+            if bbox['maxy'] < pt[1]:
-+                bbox['maxy'] = pt[1]
-+            elif bbox['miny'] > pt[1]:
-+                bbox['miny'] = pt[1]
-+                
-+            if bbox['maxx'] < pt[0]:
-+                bbox['maxx'] = pt[0]
-+            elif bbox['minx'] > pt[0]:
-+                bbox['minx'] = pt[0]  
-+
-+        return bbox
-+
-+    def SetVectMap(self, vectMap):
-+        self.vectMap = vectMap
-+
-+    def AddedFeature(self, new_geom, cat):
-+
-+        layer = cat.keys()[0]
-+        cat = cat.values()[0][0]
-+
-+        bbox = self._getBbox(new_geom)
-+        grass_region = self._create_grass_region_env(bbox)
-+
-+        #TODO temp rast
-+        patch_rast = "temp_scatt_plt_patch at class"
-+        self._rasterize(grass_region, layer, cat, patch_rast)
-+
-+        region = self.an_data.GetRegion()
-+
-+        UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastIn(cat))
-+
-+        return [cat]
-+
-+    def DeletedAreas(self, old_geoms, old_areas_cats):
-+
-+        updated_cats = []
-+        #for i in range(len(old_geoms)):
-+        #    self._updateCatRast(old_geoms[i], old_areas_cats[i], updated_cats)
-+
-+        return updated_cats
-+
-+    def ChangedVertex(self, new_geom, new_areas_cats, old_geom, old_areas_cats):
-+        #TODO possible optimization - bbox only of vertex and its two neighbours
-+
-+        updated_cats = []
-+        self._updateCatRast(old_geom, old_areas_cats, updated_cats)
-+        self._updateCatRast(new_geom, new_areas_cats, updated_cats)
-+        
-+        return updated_cats
-+
-+    def findLineDiff(geom1, geom2):
-+
-+        pass
-+        #for pt1 in geom1:
-+
-+    def MovedFeatures(self, old_geoms, old_areas_cats, new_areas_cats, move):
-+        #TODO possible optimization - bbox only of vertex and its two neighbours
-+
-+        updated_cats = []
-+        for i in range(len(old_geoms)):
-+            self._updateCatRast(old_geoms[i], old_areas_cats[i], updated_cats)
-+            
-+            new_geom = []
-+            for pt in old_geoms[i]:
-+                new_geom_pt = (pt[0] + move[0], pt[1] + move[1])
-+                new_geom.append(new_geom_pt)
-+
-+            self._updateCatRast(new_geom, new_areas_cats[i], updated_cats)
-+
-+            new_areas_cats = old_geoms[i]
-+
-+        return updated_cats
-+
-+    def _updateCatRast(self, geom, areas_cats, updated_cats):
-+
-+        rasterized_cats = []
-+        for c in range(len(areas_cats)):
-+
-+            if not areas_cats[c]:
-+                continue
-+
-+            layer = areas_cats[c].keys()[0]
-+            cat =  areas_cats[c][layer][0]
-+
-+            if cat in rasterized_cats:
-+                continue
-+
-+            rasterized_cats.append(cat)
-+            updated_cats.append(cat)
-+
-+            bbox = self._getBbox(geom)
-+            grass_region = self._create_grass_region_env(bbox)
-+
-+            #TODO hack
-+            patch_rast = "pokus at class"
-+            self._rasterize(grass_region, layer, cat, patch_rast)
-+
-+            region = self.an_data.GetRegion()
-+            UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastIn(cat))
-+
-+
-+    def _rasterize(self, grass_region, layer, cat, out_rast):
-+
-+        #TODO different thread may be problem when user edits map
-+        ret, text, msg = RunCommand("v.build",
-+                                      map = self.vectMap,
-+                                      getErrorMsg = True,
-+                                      read = True)#,
-+
-+        #TODO thread problem with env variable remove it!!!!
-+        environs = os.environ.copy()
-+        environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
-+
-+        ret, text, msg = RunCommand("v.to.rast",
-+                                    input = self.vectMap,
-+                                    use = "cat",
-+                                    layer = str(layer),
-+                                    cat = str(cat),
-+                                    output = out_rast,
-+                                    getErrorMsg = True,
-+                                    read = True,
-+                                    overwrite = True,
-+                                    env = environs)
-+    def _create_grass_region_env(self, bbox):
-+
-+        region = self.an_data.GetRegion()
-+        new_region = {}
-+
-+        if bbox["maxy"] <= region["s"]:
-+            return 0
-+        elif bbox["maxy"] >= region["n"]:
-+            new_region["n"] = bbox["maxy"]
-+        else:
-+            new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
-+
-+        if bbox["miny"] >= region["n"]:
-+            return 0
-+        elif bbox["miny"] <= region["s"]:
-+            new_region["s"] = bbox["miny"]
-+        else:
-+            new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
-+
-+        if bbox["maxx"] <= region["w"]:
-+            return 0
-+        elif bbox["maxx"] >= region["e"]:
-+            new_region["e"] = bbox["maxx"]
-+        else:
-+            new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
-+
-+        if bbox["minx"] >= region["e"]:
-+            return 0
-+        elif bbox["minx"] <= region["w"]:
-+            new_region["w"] = bbox["minx"]
-+        else:
-+            new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
-+
-+        #TODO check regions resolutin
-+        new_region["nsres"] = region["nsres"]
-+        new_region["ewres"] = region["ewres"]
-+
-+        return {"GRASS_REGION" :  grass.region_env(**new_region)}
-+
-+class AnalyzedData:
-+
-+    def __init__(self):
-+        
-+        self.bands = []
-+        self.bands_info = {}
-+
-+        self.region = None
-+
-+    def GetRegion(self):
-+        return self.region
-+
-+    def Create(self, bands):
-+
-+        self.bands = bands
-+        self.region = None
-+
-+        ret, region, msg = RunCommand("g.region",
-+                                      flags = "gp",
-+                                      getErrorMsg = True,
-+                                      read = True)
-+
-+        if  ret != 0:
-+            raise GException("g.region failed:\n%s" % msg)
-+
-+
-+        self.bands_info = {}
-+        for b in bands:
-+            self.bands_info[b] = self._getRasterInfo(b)
-+            if self.bands_info[b]["datatype"] != "CELL":
-+                raise GException(_("Raster <%s> is not <CELL> type.") % (b))
-+            #TODO size of raster check
-+
-+        self.region = self._parseRegion(region)
-+
-+    def _getRasterInfo(self, rast):
-+        """
-+        """
-+        ret, out, msg = RunCommand("r.info",
-+                                    map = rast,
-+                                    flags = "rg",
-+                                    getErrorMsg = True,
-+                                    read = True)
-+
-+        if  ret != 0:
-+            raise GException("r.info failed:\n%s" % msg)
-+
-+        out = out.split("\n")
-+        raster_info = {} 
-+
-+        for b in out:
-+            if not b.strip():
-+                continue
-+            k, v = b.split("=")
-+            if k == "datatype":
-+                pass
-+            elif k in ['rows', 'cols', 'cells', 'min', 'max']:
-+                v = int(v)
-+            else:
-+                v = float(v)
-+
-+            raster_info[k] = v
-+
-+        return raster_info
-+
-+    def GetBands(self):
-+        return self.bands
-+
-+    def GetBandInfo(self, band_id):
-+        band = self.bands[band_id]
-+        return self.bands_info[band]
-+
-+    def _parseRegion(self, region_str):
-+
-+        region = {}
-+        region_str = region_str.splitlines()
-+
-+        for param in region_str:
-+            k, v = param.split("=")
-+            if k in ["rows", "cols", "cells"]:
-+                v = int(v)
-+            else:
-+                v = float(v)
-+            region[k] = v
-+
-+        return region
-+
-+class ScattPlotsCondsData:
-+
-+    def __init__(self, an_data):
-+
-+        self.an_data = an_data
-+
-+        #TODO
-+        self.max_n_cats = 10
++        self.SetVirtualSize(self.GetBestVirtualSize())
+         self.Layout()
+         
+     def UpdatePlots(self, group, currentCat, stats_data):
+@@ -138,7 +177,7 @@
+         
+     def UpdateCategory(self, cat):
+         self.currentCat = cat
+-        
 +    
-+        self.dtype = 'uint8'
-+        self.type = 1;
-+        self.CleanUp()
-+
-+    def CleanUp(self):
-+    
-+        self.cats = {}
-+
-+        self.n_scatts = -1
-+        self.n_bands = -1
-+
-+        for cat_id in self.cats.keys():
-+            self.DeleteCategory(cat_id)
-+
-+    def Create(self, n_bands):
-+
-+        self.CleanUp()
-+
-+        self.n_scatts =  (n_bands - 1) * n_bands / 2;
-+        self.n_bands = n_bands
-+
-+        self.AddCategory(cat_id = 0)
-+
-+    def AddCategory(self, cat_id):
-+
-+        if cat_id not in self.cats.keys():
-+            self.cats[cat_id] = {}
-+            return cat_id
-+        return -1
-+
-+    def DeleteCategory(self, cat_id):
-+
-+        if cat_id not in self.cats.keys():
-+            return False
-+
-+        for scatt in self.cats[cat_id].itervalues():
-+            del scatt['np_vals']
-+
-+        del self.cats[cat_id]
-+
-+        return True
-+
-+    def GetCatScatts(self, cat_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return False
-+
-+        return self.cats[cat_id].keys()
-+
-+
-+    def AddScattPlot(self, cat_id, scatt_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return -1
-+
-+        if self.cats[cat_id].has_key(scatt_id):
-+            return 0
-+
-+        b_i = self.GetBandsInfo(scatt_id)
-+
-+        shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
-+
-+        np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
-+        np_vals.flush()
-+
-+        self.cats[cat_id][scatt_id] = {
-+                                        'np_vals' : np_vals
-+                                      }
-+
-+        return 1
-+
-+    def GetBandsInfo(self, scatt_id):
-+        b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
-+
-+        b1_info = self.an_data.GetBandInfo(b1)
-+        b2_info = self.an_data.GetBandInfo(b2)
-+
-+        bands_info = {'b1' : b1_info,
-+                      'b2' : b2_info}
-+
-+        return bands_info
-+
-+    def DeleScattPlot(self, cat_id, scatt_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return False
-+
-+        if not self.cats[cat_id].has_key(scatt_id):
-+            return False
-+
-+        del self.cats[cat_id][scatt_id]
-+        return True
-+
-+    def GetValuesArr(self, cat_id, scatt_id):
-+
-+        if not self.cats.has_key(cat_id):
-+            return None
-+
-+        if not self.cats[cat_id].has_key(scatt_id):
-+            return None
-+
-+        return self.cats[cat_id][scatt_id]['np_vals']
-+
-+    def GetData(self, requested_dt):
-+        
-+        cats = {}
-+        for cat_id, scatt_ids in requested_dt.iteritems():
-+            if not cats.has_key(cat_id):
-+                cats[cat_id] = {}
-+            for scatt_id in scatt_ids:
-+                # if key is missing condition is always True (full scatter plor is computed)
-+                if self.cats[cat_id].has_key(scatt_id):
-+                    cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
-+                                              'bands_info' : self.GetBandsInfo(scatt_id)}
-+                        
-+        return cats
-+
-+    def SetData(self, cats):
-+        
-+        for cat_id, scatt_ids in cats.iteritems():            
-+            for scatt_id in scatt_ids:
-+                # if key is missing condition is always True (full scatter plor is computed)
-+                if self.cats[cat_id].has_key(scatt_id):
-+                    self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
-+                   
-+class ScattPlotsData(ScattPlotsCondsData):
-+
-+    def __init__(self, an_data):
-+
-+        self.cats_rasts_out = {}
-+        self.cats_rasts_in = {}    
-+        self.scatts_ids = []    
-+
-+        ScattPlotsCondsData.__init__(self, an_data)
-+
-+        self.dtype = 'uint32'
-+
-+        #TODO
-+        self.type = 0
-+
-+    def AddCategory(self, cat_id):
-+        cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
-+        if cat_id < 0:
-+            return cat_id
-+
-+        for scatt_id in self.scatts_ids:
-+            ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
-+
-+        if cat_id == 0:
-+            self.cats_rasts_in[cat_id] = None
-+            self.cats_rasts_out[cat_id] = None
-+        else:
-+            self.cats_rasts_in[cat_id] = grass.tempfile()
-+            self.cats_rasts_out[cat_id] = grass.tempfile()
-+
-+        region = self.an_data.GetRegion()
-+        CreateCatRast(region, self.cats_rasts_in[cat_id])   
-+
-+        return cat_id
-+
-+    def DeleteCategory(self, cat_id):
-+
-+        ScattPlotsCondsData.DeleteCategory(self, cat_id)
-+
-+        grass.try_remove(self.cats_rasts_in[cat_id])
-+        del self.cats_rasts_in[cat_id]
-+
-+        grass.try_remove(self.cats_rasts_out[cat_id])
-+        del self.cats_rasts_out[cat_id]
-+
-+        return True
-+
-+    def AddScattPlot(self, scatt_id):
-+        
-+        if scatt_id in self.scatts_ids:
-+            return False
-+
-+        self.scatts_ids.append(scatt_id)
-+        for cat_id in self.cats.iterkeys():
-+                ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
-+
-+        return True
-+
-+    def DeleteScatterPlot(self, scatt_id):
-+        
-+        if scatt_id not in self.scatts_ids:
-+            return False
-+
-+        self.scatts_ids.remove(scatt_id)
-+
-+        for cat_id in self.cats.iterkeys():
-+                ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
-+
-+        return True
-+
-+    def GetScatt(self, scatt_id):
-+        if scatt_id not in self.scatts_ids:
-+            return False
-+
-+        scatts = {}
-+        for cat_id in self.cats.iterkeys():
-+            scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
-+                              'bands_info' : self.GetBandsInfo(scatt_id)}
-+        return scatts
-+
-+    def CleanUp(self):
-+
-+        ScattPlotsCondsData.CleanUp(self)        
-+        for tmp in self.cats_rasts_in:
-+            grass.try_remove(tmp) 
-+        for tmp in self.cats_rasts_out:
-+            grass.try_remove(tmp) 
-+
-+        self.cats_rasts_out = {}
-+        self.cats_rasts_in = {}
-+
-+    def GetCatRastIn(self, cat_id):
-+        return self.cats_rasts_in[cat_id]
-+
-+    def GetCatRastOut(self, cat_id):
-+        return self.cats_rasts_out[cat_id]
-+
-+    def GetCatsRastsIn(self):
-+        max_cat_id = max(self.cats_rasts_in.keys())
-+
-+        cats_rasts_in = [''] * (max_cat_id + 1)
-+        for i_cat_id, i_rast in self.cats_rasts_in.iteritems():
-+            cats_rasts_in[i_cat_id] = i_rast
-+
-+        return cats_rasts_in
-+
-+    def GetCatsRastsOut(self):
-+        max_cat_id = max(self.cats_rasts_out.keys())
-+
-+        cats_rasts_out = [''] * (max_cat_id + 1)
-+        for i_cat_id, i_rast in self.cats_rasts_out.iteritems():
-+            cats_rasts_out[i_cat_id] = i_rast
-+
-+        return cats_rasts_out
-+
-+#TODO move to utils?
-+def idScattToidBands(scatt_id, n_bands):
-+ 
-+    n_b1 = n_bands - 1
-+
-+    band_1 = (int) ((2 * n_b1 + 1 - sqrt(((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
-+
-+    return band_1, band_2
-+
-+
-+def idBandsToidScatt(band_1_id, band_2_id, n_bands):
-+
-+    if band_2_id <  band_1_id:
-+        tmp = band_1
-+        band_1_id = band_2_id
-+        band_2_id = tmp
-+
-+    n_b1 = n_bands - 1
-+
-+    scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
-+
-+    return scatt_id
-+
+     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,133 @@
+@@ -0,0 +1,134 @@
 +"""!
 + at package scatt_plot.gthreading
 +
@@ -1481,6 +548,8 @@
 +
 +            ret = None
 +            exception = None
++            
++            #to
 +            #try:
 +            ret = vars()['callable'](*args, **kwds)
 +            #except Exception as e:
@@ -1490,7 +559,6 @@
 +
 +            time.sleep(.1)
 +
-+          
 +            if self.receiver:
 +                event = wxCmdDone(type = 'cmd',
 +                                  kwds = kwds,
@@ -1509,11 +577,11 @@
 +        if self.requestQ.empty():
 +            self._want_abort_all = False
 \ No newline at end of file
-Index: gui/wxpython/scatt_plot/dialogs.py
+Index: gui/wxpython/scatt_plot/dialogs_iclass.py
 ===================================================================
---- gui/wxpython/scatt_plot/dialogs.py	(revision 0)
-+++ gui/wxpython/scatt_plot/dialogs.py	(working copy)
-@@ -0,0 +1,612 @@
+--- 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
 +
@@ -1532,122 +600,127 @@
 +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 core import globalvar
++from core.gcmd import GException, GError, RunCommand
 +
 +from gui_core.gselect import Select
-+from gui_core.widgets import GNotebook
 +
 +from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars    import MainToolbar, CategoriesToolbar
-+from scatt_plot.sc_pl_core  import Core, idBandsToidScatt
-+from scatt_plot.plots       import ScatterPlotWidget
++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 ScattPlotMainDialog(wx.Dialog):
++class IClassScatterPlotsPanel(wx.Panel):
 +    def __init__(self, parent, giface, iclass_mapwin = None,
-+                 id = wx.ID_ANY, title = _("GRASS GIS Interactive Scatter Plot Tool"),
-+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+    
-+        wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
-+        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
++                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
 +
-+        #TODO remove iclass parameter
++        #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)
-+        
-+        self.mainPanel = wx.Panel(parent=self)        
-+        self.notebook = GNotebook(parent = self.mainPanel,
-+                                  style = FN.FNB_FANCY_TABS | FN.FNB_BOTTOM |
-+                                          FN.FNB_NO_X_BUTTON)
++        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        self._createCategoryPanel(self)
 +
-+        # Fancy gui
-+        self._mgr = wx.aui.AuiManager(self)
-+        self._addPanes()
-+        self._mgr.Update()
++        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
 +
-+        self._createCategoryPage()
-+       
-+        self.edit_cat_tools = {
-+                                'editCatAdd' : {
-+                                                'toggle' : False,
-+                                                'type' : 'add'
-+                                                },
-+                                'editCatRemove' : {
-+                                                   'toggle' : False,
-+                                                   'type' : 'remove'
-+                                                  }
-+                              }
-+        self._doLayout()
-+        self.Bind(wx.EVT_CLOSE, self.OnCloseDialog)
++        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)
 +
-+        dlgSize = (220, 400)
-+        self.SetMinSize(dlgSize)
-+        self.SetInitialSize(dlgSize)
++        
++        #self.SetSashGravity(0.5)
++        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
++        self.Layout()
++        #self.SetAutoLayout(1)
 +
-+        #fix goutput's pane size (required for Mac OSX)
-+        #if self.gwindow:         
-+        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++    def NewScatterPlot(self, scatt_id):
++        return self.plot_panel.NewScatterPlot(scatt_id)
 +
-+    def _doLayout(self):
++    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()
 +
-+        sizer = wx.BoxSizer(wx.VERTICAL)
++    def _createCategoryPanel(self, parent):
++        self.catsPanel = wx.Panel(parent = parent)
++        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
++                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
 +
-+        sizer.Add(item = self.notebook, proportion = 1,
-+                  flag = wx.EXPAND)
++        self.catsPanel.SetMaxSize((-1, 150))
 +
-+        self.mainPanel.SetSizer(sizer)
++        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)
 +
-+        sizer.Fit(self)  
-+        self.Layout()
++        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++        self.catsPanel.SetSizer(catsSizer)
 +
-+    #TODO split to panel?
-+    def _createCategoryPage(self):
-+        catsPanel = wx.Panel(parent = self)
 +
++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.notebook.AddPage(page = catsPanel, 
-+                              text=_('Categories'), 
-+                              name = 'categories')
++        self.scatt_mgr = scatt_mgr
 +
-+        self.cats_list = CategoryListCtrl(parent = catsPanel, 
-+                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
-+        self.toolbars['catsList'] = CategoriesToolbar(parent = catsPanel, 
-+                                                      cats_list = self.cats_list,
-+                                                      scatts_dlg = self)
++        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
 +
-+        AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
++        #self._createCategoryPanel()
++        # Fancy gui
++        self._mgr = aui.AuiManager(self.mainPanel)
++        #self._mgr.SetManagedWindow(self)
 +
-+        catsSizer = wx.BoxSizer(wx.VERTICAL)
++        self._mgr.Update()
 +
-+        catsSizer.Add(item = self.toolbars['catsList'], proportion = 0)
-+        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND)
++        self._doLayout()
++        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
 +
-+        catsPanel.SetSizer(catsSizer)
++        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 _addPanes(self):
-+        """!Adds toolbar pane and pane with tabs"""
-+        self._mgr.AddPane(self.toolbars['mainToolbar'],
-+                              wx.aui.AuiPaneInfo().
-+                              Name("pointlisttools").Caption(_("Point cats_list toolbar")).
-+                              ToolbarPane().Top().Row(0).
-+                              Dockable(False).
-+                              CloseButton(False).Layer(0))
++    def _doLayout(self):
 +
-+        self._mgr.AddPane(self.mainPanel,
-+                              wx.aui.AuiPaneInfo().
-+                              Name("tabs").CaptionVisible(visible = False).
-+                              Center().
-+                              Dockable(False).
-+                              CloseButton(False).Layer(0))
++        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()
@@ -1656,91 +729,202 @@
 +    def OnSettings(self, event):
 +        pass
 +
-+    def OnSetData(self, event):
++    def NewScatterPlot(self, scatt_id):
++        #TODO needs to be resolved (should be in this class)
 +
-+        dlg = SetDataDialog(parent=self)        
++        scatt = ScatterPlotWidget(parent = self.mainPanel, 
++                                  scatt_mgr = self.scatt_mgr, 
++                                  scatt_id = scatt_id)
 +
-+        if dlg.ShowModal() == wx.ID_OK:
-+            bands = dlg.GetBands()
-+            self.scatt_mgr.SetData(bands)
-+        
-+        dlg.Destroy()
++        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()
 +
-+    def NewScatterPlot(self, scatt_id):
-+        #TODO needs to be resolved (should be in this class)
-+        scatt_dlg = ScatterPlotDialog(parent = self, scatt_mgr = self.scatt_mgr, scatt_id = scatt_id)
-+        return scatt_dlg.GetPlot()
++        return scatt
 +
-+    def OnSettings(self, event):
-+        pass
++    def GetScattMgr(self):
++        return  self.scatt_mgr
 +
-+    def OnAddScattPl(self, event):
++class CategoryListCtrl(wx.ListCtrl,
++                       listmix.ListCtrlAutoWidthMixin,
++                       listmix.TextEditMixin):
 +
-+        bands = self.scatt_mgr.GetBands()
-+        if not bands:
-+            GError(_('No data set for scatter plot.'))
-+            return
++    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
 +
-+        dlg = AddScattPlotDialog(parent = self, bands = bands)
++        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)
 +        
-+        if dlg.ShowModal() == wx.ID_OK:
-+            self.scatt_mgr.AddScattPlot(dlg.GetScattId())
++        self.cats_mgr = cats_mgr
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++        self.rightClickedItemIdx = wx.NOT_FOUND
 +        
-+        dlg.Destroy()
++        listmix.ListCtrlAutoWidthMixin.__init__(self)
 +
-+    def EditCatAdd(self):
-+        self._setEditCat(tool_name = 'editCatAdd')
++        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 EditCatRemove(self):
-+        self._setEditCat(tool_name = 'editCatRemove')
++    def Update(self, **kwargs):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
 +
-+    def _setEditCat(self, tool_name):
++    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)
 +        
-+        if self.edit_cat_tools[tool_name]['toggle'] == False:
-+            
-+            for i_tool_name in self.edit_cat_tools.iterkeys():
-+                if i_tool_name == tool_name:
-+                    continue
++        self.Select(row)
++        
++    def Populate(self, columns):
++        for i, col in enumerate(columns):
++            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
 +
-+                self.edit_cat_tools[i_tool_name]['toggle'] = False
++        self.SetColumnWidth(0, 100)
++        self.SetColumnWidth(1, 100)
++        
++    def AddCategory(self):
 +
-+                toolbar = self.toolbars['catsList']
-+                toolbar.ToggleTool(vars(toolbar)[i_tool_name], False)
++        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]
 +            
-+            self.edit_cat_tools[tool_name]['toggle'] = True
-+            self.scatt_mgr.EditCat(edit_type = self.edit_cat_tools[tool_name]['type'])
-+            return
++            cats.append(cat_id)
 +
-+        self.scatt_mgr.EditCat(edit_type = None)
-+        self.edit_cat_tools[tool_name]['toggle'] = False
++            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 GetScattMgr(self):
-+        return  self.scatt_mgr
++    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
 +
-+class SetDataDialog(wx.Dialog):
++        if currentCol == 1:
++            dlg = wx.ColourDialog(self)
++            dlg.GetColourData().SetChooseFull(True)
 +
-+    def __init__(self, parent, id  = wx.ID_ANY):
++            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)
 +        
-+        wx.Dialog.__init__(self, parent, title = ("Select imagery group "), id = id)
++        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]
 +
-+        self.bands = []
++        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()
-+        self.group.SetValue("B_sk")
 +
 +    def _createWidgets(self):
 +
 +        self.labels = {}
 +        self.params = {}
 +
-+        self.group_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Name of raster group for input data:"))
++        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
 +
-+        self.group = Select(parent = self, type = 'group',
-+                            size = globalvar.DIALOG_GSELECT_SIZE)
++        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)
 +        
@@ -1755,9 +939,12 @@
 +
 +        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
 +
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.group_label, 
-+                                                    sel = self.group))
++        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)
 +
@@ -1801,10 +988,6 @@
 +
 +        return selSizer
 +
-+    def GetBands(self):
-+
-+        return self.bands
-+
 +    def OnClose(self, event):
 +        """!Close dialog
 +        """
@@ -1815,30 +998,51 @@
 +    def OnOk(self, event):
 +        """!
 +        """
-+        ret, stdout, err_msg = RunCommand("i.group",
-+                                      getErrorMsg = True,
-+                                      read = True,
-+                                      quiet = True,
-+                                      group = self.group.GetValue().strip(),
-+                                      flags = 'g')
++        band_1 = self.band_1_ch.GetSelection()
++        band_2 = self.band_2_ch.GetSelection()
 +
-+        if ret != 0:
-+            GError("%s module failed:\n%s" % ("<i.group>", err_msg))
++
++        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.bands = stdout.split('\n')
++        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
 +
-+        for band in self.bands[:]:
-+            if not band:
-+                self.bands.remove(band)
-+    
 +        event.Skip()
 +
-+    #TODO catch event or...
-+    def GetSelectedCatId(self):
-+        
-+        return self.cats_list.GetSelectedCatId()
++    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):
@@ -1961,171 +1165,118 @@
 +
 +    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
 +
-+class ScatterPlotDialog(wx.Dialog):
-+    def __init__(self, parent, scatt_mgr, scatt_id,
-+                 id = wx.ID_ANY, title = _("Test plot"),
-+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+    
-+        wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
-+        self.scatt = ScatterPlotWidget(parent = self, 
-+                                       scatt_mgr = scatt_mgr, 
-+                                       scatt_id = scatt_id)
++ at brief Scatter plot - toolbars
 +
-+    def GetPlot(self):
-+        return self.scatt
++Classes:
++ - toolbars::MainToolbar
 +
-+    def _doLayout(self):
-+        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
-+        self.main_sizer.Add(self.self)
++(C) 2013 by the GRASS Development Team
 +
-+        self.panel.SetSizer(self.main_sizer)
-+        self.main_sizer.Fit(self)
-+    
-+    def OnPlotClosed(self, scatt_id):
-+        self.Destroy()
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
 +
-+class CategoryListCtrl(wx.ListCtrl,
-+                       listmix.ListCtrlAutoWidthMixin,
-+                       listmix.TextEditMixin):
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
 +
-+    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 = ((_('Category name'), 'name'),
-+                        (_('Color'), 'color'))
-+        self.Populate(columns = self.columns)
-+        
-+        self.cats_mgr = cats_mgr
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++import wx
 +
-+        self.rightClickedItemIdx = wx.NOT_FOUND
-+        
-+        listmix.ListCtrlAutoWidthMixin.__init__(self)
++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
 +
-+        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()))
++class MainToolbar(BaseToolbar):
++    """!Main toolbar
++    """
++    def __init__(self, parent, scatt_mgr):
++        BaseToolbar.__init__(self, parent)
++        self.scatt_mgr = scatt_mgr
 +
-+    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.InitToolbar(self._toolbarData())
 +        
-+        self.Select(row)
-+        
-+    def Populate(self, columns):
-+        for i, col in enumerate(columns):
-+            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++        # realize the toolbar
++        self.Realize()
 +
-+        self.SetColumnWidth(0, 100)
-+        self.SetColumnWidth(1, 100)
-+        
-+    def AddCategory(self):
++    def _toolbarData(self):
 +
-+        self.cats_mgr.addedCategory.disconnect(self.Update)
-+        cat_id = self.cats_mgr.AddCategory()
-+        self.cats_mgr.addedCategory.connect(self.Update)
++        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'))
++                }
 +
-+        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)
++        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),                    
++                                    ))
 +
-+            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): 
-+        self.cats_mgr.SetSelectedCat(event.GetIndex() + 1)
++    def GetToolId(self, toolName): #TODO can be useful in base
 +
-+        event.Skip()
++        return vars(self)[toolName]            
 +
-+    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 SetPloltsMode(self, event, tool_name):
 +
-+    def OnEdit(self, event):
-+        currentItem = event.m_itemIndex
-+        currentCol = event.m_col
++        #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]
 +
-+        if currentCol == 1:
-+            dlg = wx.ColourDialog(self)
-+            dlg.GetColourData().SetChooseFull(True)
++                self.ToggleTool(i_tool_id, False)
++            self.scatt_mgr.SetPlotsMode(mode = tool_name)
++            return
 +
-+            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
++        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)
@@ -2150,9 +1301,9 @@
 +
 +import wx
 +
-+from icons.icon        import MetaIcon
++from icons.icon import MetaIcon
 +from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd         import RunCommand
++from core.gcmd import RunCommand
 +
 +class MainToolbar(BaseToolbar):
 +    """!Main toolbar
@@ -2242,7 +1393,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/core_c.py	(revision 0)
 +++ gui/wxpython/scatt_plot/core_c.py	(working copy)
-@@ -0,0 +1,227 @@
+@@ -0,0 +1,226 @@
 +"""!
 + at package scatt_plot.scatt_plot
 +
@@ -2323,8 +1474,8 @@
 +                           pointer(scatt_conds_c),
 +                           pointer(char_bands),
 +                           n_bands,
++                           pointer(char_cats_rasts_in),
 +                           pointer(sccats_c),
-+                           pointer(char_cats_rasts_in),
 +                           pointer(char_cats_rasts_out))
 +
 +    I_sc_free_cats(pointer(sccats_c))
@@ -2430,14 +1581,13 @@
 +    cell_head = _regionToCellHead(region)
 +    
 +    
-+    cat_rast
 +    I_insert_patch_to_cat_rast(patch_rast, 
-+                                     pointer(cell_head), 
-+                                     cat_rast)
++                               pointer(cell_head), 
++                               cat_rast)
 +
 +    #print re
 +    #output_queue.put((ret, scatts))
-+    #return (ret, scatts)
++     #return (ret, scatts)
 +
 +"""
 +class A:
@@ -2474,9 +1624,10 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/__init__.py	(revision 0)
 +++ gui/wxpython/scatt_plot/__init__.py	(working copy)
-@@ -0,0 +1,8 @@
+@@ -0,0 +1,9 @@
 +all = [
 +    'dialogs',
++    'gui_iclass',
 +    'gthreading',
 +    'plots',
 +    'sc_pl_core',
@@ -2487,7 +1638,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/plots.py	(revision 0)
 +++ gui/wxpython/scatt_plot/plots.py	(working copy)
-@@ -0,0 +1,199 @@
+@@ -0,0 +1,223 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -2505,6 +1656,7 @@
 +import wx
 +import numpy as np
 +import random
++
 +try:
 +    haveMatPlot = True
 +    import matplotlib
@@ -2519,7 +1671,7 @@
 +class ScatterPlotWidget(wx.Panel):
 +    def __init__(self, parent, scatt_id, scatt_mgr,
 +                 id = wx.ID_ANY):
-+    
++
 +        wx.Panel.__init__(self, parent, id)
 +
 +        self.parent = parent
@@ -2533,7 +1685,29 @@
 +        self.cidpress = None
 +        self.cidrelease = None
 +
-+    def StartCategoryEdit(self):
++        self.SetSize((200, 100))
++        self.Layout()
++
++    def SetMode(self, mode):
++        self._deactivateMode()
++
++        if mode == 'zoom':
++            self.toolbar.zoom()
++        elif mode == 'pan':
++            self.toolbar.pan()
++        elif mode in ["add", "remove"]:
++            self._startCategoryEdit()
++
++    def _deactivateMode(self):
++
++        if self.toolbar._active == "PAN":
++            self.toolbar.pan()
++        elif self.toolbar._active == "ZOOM":
++            self.toolbar.zoom()
++
++        self._stopCategoryEdit()
++
++    def _startCategoryEdit(self):
 +        'connect to all the events we need'
 +        self.cidpress = self.canvas.mpl_connect(
 +            'button_press_event', self.OnPress)
@@ -2572,7 +1746,7 @@
 +
 +            self.scatt_mgr.SetEditCatData(self.scatt_id, bbox)
 +
-+    def StopCategoryEdit(self):
++    def _stopCategoryEdit(self):
 +        'disconnect all the stored connection ids'
 +
 +        if self.cidpress:
@@ -2587,7 +1761,7 @@
 +        # 5x4 inches, 100 dots-per-inch
 +        #
 +        self.dpi = 100
-+        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
++        self.fig = Figure((1.0, 1.0), dpi=self.dpi)
 +        self.canvas = FigCanvas(self, -1, self.fig)
 +        
 +        # Since we have only one plot, we can use add_axes 
@@ -2595,8 +1769,8 @@
 +        # configuration tool in the navigation toolbar wouldn't
 +        # work.
 +        #
-+        self.axes = self.fig.add_subplot(111)
-+        
++        #elf.axes = self.fig.add_subplot(111)
++        self.axes = self.fig.add_axes([0,0,1,1])
 +        # Bind the 'pick' event for clicking on one of the bars
 +        #
 +        self.canvas.mpl_connect('button_press_event', self.on_pick)
@@ -2605,14 +1779,14 @@
 +        # Create the navigation toolbar, tied to the canvas
 +        #
 +        self.toolbar = NavigationToolbar(self.canvas)
++        #print  vars(self.toolbar)
++        #print [method for method in dir(self.toolbar) if callable(getattr(self.toolbar, method))]
 +        
 +    def _doLayout(self):
 +        
 +        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
 +        self.main_sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
-+        self.main_sizer.Add(self.toolbar, 0, wx.EXPAND)
-+        self.main_sizer.AddSpacer(10)
-+        
++        #self.main_sizer.Add(self.toolbar, 0, wx.EXPAND)        
 +        self.SetSizer(self.main_sizer)
 +        self.main_sizer.Fit(self)
 +    
@@ -2646,14 +1820,15 @@
 +            
 +            #self.axes.set_xlim((0, 270))
 +            #self.axes.set_ylim((0, 270))
-+            np.savetxt("/home/ostepok/Desktop/data.txt", scatt['np_vals'], fmt = '%d') 
++            #np.savetxt("/home/ostepok/Desktop/data.txt", scatt['np_vals'], fmt = '%d') 
 +
 +
 +            #TODO needs optimization
 +            img = self.axes.imshow(masked_cat, cmap = cmap,
 +                                               origin = 'lower',
 +                                               extent = (b1_i['min'] - 0.5, b1_i['max'] + 0.5, b2_i['min'] - 0.5, b2_i['max'] + 0.5), 
-+                                               interpolation='nearest')
++                                               interpolation='nearest',
++                                               aspect = "auto")
 +            
 +            self.canvas.draw()
 +
@@ -2688,55 +1863,1253 @@
 +        self.parent.OnPlotClosed(self.scatt_id)
 +        self.Destroy()
 \ No newline at end of file
-Index: gui/wxpython/mapdisp/toolbars.py
+Index: gui/wxpython/scatt_plot/controllers.py
 ===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57336)
-+++ gui/wxpython/mapdisp/toolbars.py	(working copy)
-@@ -243,7 +243,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)))
-         
-     def OnDecoration(self, event):
-         """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
-===================================================================
---- gui/wxpython/mapdisp/frame.py	(revision 57336)
-+++ gui/wxpython/mapdisp/frame.py	(working copy)
-@@ -207,6 +207,7 @@
-         #
-         self.dialogs = {}
-         self.dialogs['attributes'] = None
-+        self.dialogs['scatt_plot'] = None
-         self.dialogs['category'] = None
-         self.dialogs['barscale'] = None
-         self.dialogs['legend'] = None
-@@ -1301,6 +1302,19 @@
-         """!Returns toolbar with zooming tools"""
-         return self.toolbars['map']
- 
-+    def OnScatterplot2(self, event):
-+        """!Init interactive scatterplot tools
+--- gui/wxpython/scatt_plot/controllers.py	(revision 0)
++++ gui/wxpython/scatt_plot/controllers.py	(working copy)
+@@ -0,0 +1,563 @@
++"""!
++ at package scatt_plot.controllers
++
++ at brief Controller layer for scatter plot tool.
++
++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
++
++#TODO
++import wx
++
++from core.gcmd import GException, GError, RunCommand
++
++from scatt_plot.sc_pl_core import Core, idBandsToidScatt
++from scatt_plot.plots import haveMatPlot
++
++from scatt_plot.dialogs import AddScattPlotDialog
++from scatt_plot.gthreading import gThread
++from core.gconsole import EVT_CMD_DONE
++from grass.pydispatch.signal import Signal
++
++class ScattsManager(wx.EvtHandler):
++    def __init__(self, guiparent, giface, iclass_mapwin):
++        #TODO remove iclass parameter
++        if not haveMatPlot:
++            raise GException(_("The interactive scatter plot tool needs \"Matplotlib\" package to be installed."))
++
++        wx.EvtHandler.__init__(self)
++        self.giface = giface
++        self.mapDisp  = giface.GetMapDisplay()
++
++        if iclass_mapwin:
++            self.mapWin = iclass_mapwin
++        else:
++            self.mapWin = giface.GetMapWindow()
++
++        self.guiparent = guiparent
++
++        self.show_add_scatt_plot = False
++
++        self.core = Core()
++        self.scatts_dt = self.core.GetScattsData()
++
++        self.cats_mgr = CategoriesManager(self, self.core)
++
++        self.thread = gThread(self);
++        
++        self.scatt_plts = {}
++        self.added_cats_rasts = {}
++
++        self.cats_to_update = []
++
++        self.plot_mode =  None
++
++        self.data_set = False
++
++        if iclass_mapwin: 
++            self.mapWin_conn = MapWinConnection(self, self.mapWin, self.core.CatRastUpdater())
++            self.iclass_conn = IClassConnection(self, iclass_mapwin.parent, self.cats_mgr)
++        else:
++            self.mapWin_conn = None
++            self.iclass_conn = None
++
++        self.tasks_pids = {
++                            'add_scatt' : [],
++                            'set_data' : -1,
++                            'set_data_add' : -1,
++                            'set_edit_cat_data' : -1,
++                            'mapwin_conn' : [],
++                            'render_plots' : -1
++                           }
++
++        self.Bind(EVT_CMD_DONE, self.OnThreadDone)
++
++    def SetData(self, bands):
++        self.data_set = False
++
++        if self.show_add_scatt_plot:
++            self.tasks_pids['set_data_add'] = self.thread.GetId()
++        else:
++            self.tasks_pids['set_data'] = self.thread.GetId()
++
++        self.thread.Run(callable = self.core.SetData, bands = bands)
++
++        #for i in range(1):
++        #    self.AddScattPlot(i)
++
++    def SetDataDone(self, event):
++
++        self.data_set = True
++        self.cats_mgr.InitCoreCats()
++
++    def OnOutput(self, event):
++        """!Print thread output according to debug level.
 +        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
++        print event.text
++
++    def GetBands(self):
++        return self.core.GetBands()
++
++    def AddScattPlot(self):
++        if not self.data_set and self.iclass_conn:
++            self.show_add_scatt_plot = True
++            self.iclass_conn.SetData()
++            self.show_add_scatt_plot = False
 +            return
++        if not self.data_set:
++            GError(_('No data set.'))
++            return
 +
-+        from scatt_plot.dialogs import ScattPlotMainDialog
-+        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++        dlg = AddScattPlotDialog(parent = self.guiparent, bands = self.core.GetBands())
++
++        if dlg.ShowModal() == wx.ID_OK:
++            self._addScattPlot(dlg.GetScattId())
 +        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
++        dlg.Destroy()
 +
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
++    def _addScattPlot(self, scatt_id):
++
++        self.tasks_pids['add_scatt'].append(self.thread.GetId())
++        
++        self.thread.Run(callable = self.core.AddScattPlot, scatt_id = scatt_id)
++
++    def RenderScattPlts(self):
++
++        cats_attrs = self.cats_mgr.GetCategoriesAttrs()
++        for scatt_id, scatt in self.scatt_plts.iteritems():
++            scatt_dt = self.scatts_dt.GetScatt(scatt_id)
++            scatt.Plot(scatt_dt, cats_attrs)
++
++
++    def AddScattPlotDone(self, event):
++        
++        scatt_id = event.kwds['scatt_id']
++
++        #TODO guiparent - not very good
++        self.scatt_plts[scatt_id] = self.guiparent.NewScatterPlot(scatt_id = scatt_id)
++
++        if self.plot_mode:
++            self.scatt_plts[scatt_id].SetMode(self.plot_mode)
++
++        scatt_dt = self.scatts_dt.GetScatt(scatt_id)
++        
++        cats_attrs = self.cats_mgr.GetCategoriesAttrs()
++
++        self.scatt_plts[scatt_id].Plot(scatt_dt, cats_attrs)
++        #for scatt in scatt_dt.itervalues():
++        #    del scatt 
++        self.scatt_plts[scatt_id].GetParent().Show()
++
++    def CleanUp(self):
++        self.core.CleanUp()
++
++        for scatt_id, scatt in self.scatt_plts.items():
++            scatt.CleanUp()
++            del self.scatt_plts[scatt_id]
++
++    def OnThreadDone(self, event):
++        
++        if event.exception:
++            GError(str(event.exception))
++            return
++
++        if event.pid in self.tasks_pids['mapwin_conn']:
++            self.tasks_pids['mapwin_conn'].remove(event.pid)
++            updated_cats = event.ret
++
++            for cat in updated_cats:
++                if cat not in  self.cats_to_update:
++                    self.cats_to_update.append(cat)
++
++            if not self.tasks_pids['mapwin_conn']:
++                self.tasks_pids['render_plots'] = self.thread.GetId()
++                self.thread.Run(callable = self.core.ComputeCatsScatts, 
++                                cats_ids = self.cats_to_update[:])
++                del self.cats_to_update[:]
++ 
++            return
++
++        if self.tasks_pids['render_plots'] == event.pid:
++            #TODO how to put it to the thread - kils gui
++            self.RenderScattPlts()
++            return
++            
++        if event.pid in self.tasks_pids['add_scatt']:
++            self.AddScattPlotDone(event)
++            return
++
++        if self.tasks_pids['set_data'] == event.pid:
++            self.SetDataDone(event)
++            return
++        
++        if self.tasks_pids['set_data_add'] == event.pid:
++            self.SetDataDone(event)
++            self.AddScattPlot()
++            return
++        
++        if self.tasks_pids['set_edit_cat_data'] == event.pid:
++            self.SetEditCatDataDone(event)
++            return
++
++    def SetPlotsMode(self, mode):
++
++        self.plot_mode = mode
++
++        for scatt in self.scatt_plts.itervalues():
++            scatt.SetMode(mode)
++
++    def SetEditCatData(self, scatt_id, bbox):
++        
++        value = 1
++        if self.plot_mode == 'remove':
++            value = 0
++
++        self.tasks_pids['set_edit_cat_data'] = self.thread.GetId()
++
++        sel_cat_id = self.cats_mgr.GetSelectedCat()
++        
++        if not sel_cat_id:
++            dlg = wx.MessageDialog(parent = self.guiparent,
++                      message = _("In order to select arrea in scatter plot, "
++                                  "you have to select class first.\n\n"
++                                  "There is no class yet, "
++                                  "do you want to create one?"),
++                      caption = _("No class selected"),
++                      style = wx.YES_NO)
++            if dlg.ShowModal() == wx.ID_YES:
++                self.iclass_conn.EmptyCategories()
++            return
++
++        self.thread.Run(callable = self.core.SetEditCatData, 
++                        scatt_id = scatt_id,
++                        cat_id = sel_cat_id,
++                        bbox = bbox,
++                        value = value)
++    
++    def SetEditCatDataDone(self, event):
++
++        if event.exception:
++            GError(_("Error occured during computation of scatter plot category:\n%s") , parent = self.guiparent, showTraceback = False)
++
++        self.RenderScattPlts()
++
++        cat_id = event.kwds["cat_id"]
++
++        cat_rast = self.core.GetCatRast(cat_id)
++
++
++        if cat_rast not in self.added_cats_rasts.values():
++
++            cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
++
++    
++            region = self.core.GetRegion()
++            ret, err_msg = RunCommand('r.region',
++                                      map = cat_rast,
++                                      getErrorMsg = True,
++                                      n = "%f" % region['n'],
++                                      s = "%f" % region['s'],
++                                      e = "%f" % region['e'],
++                                      w = "%f" % region['w'],
++                                      )
++
++            region = self.core.GetRegion()
++            ret, err_msg = RunCommand('r.colors',
++                                      map = cat_rast,
++                                      rules = "-",
++                                      stdin = "1 %s" % cats_attrs["color"],
++                                      getErrorMsg = True)
++
++            if ret != 0:
++                GError(_("r.region failed\n%s" % err_msg))
++
++            self.mapWin.Map.AddLayer(ltype = "raster", name =  "cat_%d" % cat_id, render = True,
++                                     command = ["d.rast", "map=%s" % cat_rast, "values=1"])                
++
++
++            if ret != 0:
++                GError(_("r.region failed\n%s" % err_msg))
++
++            self.added_cats_rasts[cat_id] = cat_rast
++
++        self.giface.updateMap.emit()
++
++    def DigitDataChanged(self, vectMap, digit):
++        
++        if self.mapWin_conn:
++            self.mapWin_conn.DigitDataChanged(vectMap, digit)
++            return 1
++        else:
++            return 0
++
++    def GetCategoriesManager(self):
++        return self.cats_mgr
++
++class CategoriesManager:
++
++    def __init__(self, scatt_mgr, core):
++
++        self.core = core
++        self.scatt_mgr = scatt_mgr
++
++        self.cats = {}
++        self.cats_ids = []
++
++        self.sel_cat_id = None
++
++        self.initialized = Signal('CategoriesManager.initialized')
++        self.setCategoryAttrs = Signal('CategoriesManager.setCategoryAttrs')
++        self.deletedCategory = Signal('CategoriesManager.deletedCategory')
++        self.addedCategory = Signal('CategoriesManager.addedCategory')
++
++    def Clear(self):
++
++        self.cats.clear()
++        del self.cats_ids[:]
++
++        self.sel_cat_id = None  
++
++    def InitCoreCats(self):
++        if self.scatt_mgr.data_set:
++            for cat_id in self.cats_ids:
++                self.core.AddCategory(cat_id)
++
++    def AddCategory(self, cat_id = None, name = None, color = None):
++
++        if cat_id is None:
++            if self.cats_ids:
++                cat_id = max(self.cats_ids) + 1
++            else:
++                cat_id = 1
++
++        if self.scatt_mgr.data_set:
++            ret = self.core.AddCategory(cat_id)
++            if ret < 0: #TODO
++                return -1;
++
++        self.cats[cat_id] = {
++                                'name' : _('Category %s' % cat_id ),
++                                'color' : "0:0:0"
++                            }
++        self.cats_ids.append(cat_id)
++
++        if name is not None:
++            self.cats[cat_id]["name"] = name
++   
++        if color is not None:
++            self.cats[cat_id]["color"] = color
++
++        self.addedCategory.emit(cat_id = cat_id,
++                                name = self.cats[cat_id]["name"], 
++                                color = self.cats[cat_id]["color"] )
++        return cat_id
++
++    def SetCategoryAttrs(self, cat_id, attrs_dict):
++        for k, v in attrs_dict.iteritems():
++            self.cats[cat_id][k] = v
++
++        self.setCategoryAttrs.emit(cat_id = cat_id, attrs_dict = attrs_dict)
++
++    def DeleteCategory(self, cat_id):
++
++        if self.scatt_mgr.data_set:
++            self.core.DeleteCategory(cat_id)
++        del self.cats[cat_id]
++        self.cats_ids.remove(cat_id)
++
++        self.deletedCategory.emit(cat_id = cat_id)
++
++    #TODO emit event?
++    def SetSelectedCat(self, cat_id):
++        self.sel_cat_id = cat_id
++
++    def GetSelectedCat(self):
++        return self.sel_cat_id
++
++    def GetCategoryAttrs(self, cat_id):
++        #TODO is mutable
++        return self.cats[cat_id]
++
++    def GetCategoriesAttrs(self):
++        #TODO is mutable
++        return self.cats
++     
++    def GetCategories(self):
++        return self.cats_ids[:]
++
++class MapWinConnection:
++    def __init__(self, scatt_mgr, mapWin, scatt_rast_updater):
++        self.mapWin = mapWin
++        self.vectMap = None
++        self.scatt_rast_updater = scatt_rast_updater
++        self.scatt_mgr = scatt_mgr
++        self.cats_mgr = scatt_mgr.cats_mgr
++
++        self.thread = self.scatt_mgr.thread
++
++        #TODO
++        self.mapWin.parent.toolbars["vdigit"].editingStarted.connect(self.DigitDataChanged)
++
++        #def ChangeMap(self, vectMap, layers_cats):
++        #     self.vectMap = vectMap
++        #     self.layers_cats = layers_cats
++
++        #ret, region, msg = RunCommand("v.to.rast",
++        #                              flags = "gp",
++        #                              getErrorMsg = True,
++        #                              read = True)
++
++    def _connectSignals(self):
++        self.digit.featureAdded.connect(self.AddFeature)
++        self.digit.areasDeleted.connect(self.DeleteAreas)
++        self.digit.featuresDeleted.connect(self.DeleteAreas)
++        self.digit.vertexMoved.connect(self.EditedFeature)
++        self.digit.vertexRemoved.connect(self.EditedFeature)
++        self.digit.lineEdited.connect(self.EditedFeature)
++        self.digit.featuresMoved.connect(self.EditedFeature)
++
++    def AddFeature(self, new_bboxs, new_areas_cats):
++        if not self.scatt_mgr.data_set:
++            return
++
++        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
++        self.thread.Run(callable = self.scatt_rast_updater.EditedFeature, 
++                        new_bboxs = new_bboxs, 
++                        old_bboxs = [], 
++                        old_areas_cats = [],
++                        new_areas_cats = new_areas_cats)
++
++    def DeleteAreas(self, old_bboxs, old_areas_cats):
++        if not self.scatt_mgr.data_set:
++            return
++
++        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
++        self.thread.Run(callable = self.scatt_rast_updater.EditedFeature, 
++                        new_bboxs = [], 
++                        old_bboxs = old_bboxs, 
++                        old_areas_cats = old_areas_cats,
++                        new_areas_cats = [])
++
++
++    def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
++        if not self.scatt_mgr.data_set:
++            return
++
++        self.scatt_mgr.tasks_pids['mapwin_conn'].append(self.thread.GetId())
++        self.thread.Run(callable = self.scatt_rast_updater.EditedFeature, 
++                        new_bboxs = new_bboxs, 
++                        old_bboxs = old_bboxs, 
++                        old_areas_cats = old_areas_cats,
++                        new_areas_cats = new_areas_cats)
++
++    def DigitDataChanged(self, vectMap, digit):
++
++        self.digit = digit
++        self.vectMap = vectMap
++
++        self.scatt_rast_updater.SetVectMap(vectMap)
++
++        self._connectSignals()
++
++class IClassConnection:
++    def __init__(self, scatt_mgr, iclass_frame, cats_mgr):
++        self.iclass_frame = iclass_frame
++        self.stats_data   = self.iclass_frame.stats_data
++        self.cats_mgr     = cats_mgr
++        self.scatt_mgr    = scatt_mgr
++
++        self.stats_data.statisticsAdded.connect(self.AddCategory)
++        self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
++        self.stats_data.allStatisticsDeleted.connect(self.DeletAllCategories)
++        self.stats_data.statisticsSet.connect(self.SetCategory)
++
++        self.iclass_frame.groupSet.connect(self.GroupSet)
++
++        self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
++        self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
++        self.cats_mgr.addedCategory.connect(self.AddStatistics)
++
++        self.iclass_frame.categoryChanged.connect(self.CategoryChanged)
++
++        self.SyncCats()
++
++    def SetData(self):
++        self.iclass_frame.AddBands()
++
++    def EmptyCategories(self):
++        self.iclass_frame.OnCategoryManager(None)
++
++    def SyncCats(self):
++        self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
++        cats = self.stats_data.GetCategories()
++        for c in cats:
++            stats = self.stats_data.GetStatistics(c)
++            self.cats_mgr.AddCategory(c, stats.name, stats.color)
++        self.cats_mgr.addedCategory.connect(self.AddStatistics)
++
++    def CategoryChanged(self, cat):
++        self.cats_mgr.SetSelectedCat(cat) 
++
++    def AddCategory(self, cat, name, color):
++        self.cats_mgr.addedCategory.disconnect(self.AddStatistics)
++        self.cats_mgr.AddCategory(cat_id = cat, name = name, color = color)
++        self.cats_mgr.addedCategory.connect(self.AddStatistics)
++
++    def DeleteCategory(self, cat):
++        self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
++        self.cats_mgr.DeleteCategory(cat)
++        self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
++
++    def DeletAllCategories(self):
++
++        self.cats_mgr.deletedCategory.disconnect(self.DeleteStatistics)
++        cats = self.stats_data.GetCategories()
++        for c in cats:
++            self.cats_mgr.DeleteCategory(c)
++        self.cats_mgr.deletedCategory.connect(self.DeleteStatistics)
++
++    def SetCategory(self, cat, stats):
++
++        self.cats_mgr.setCategoryAttrs.disconnect(self.SetStatistics)
++        cats_attr = {}
++        for attr in ['name', 'color']:
++            if stats.has_key(attr):
++                cats_attr[attr] = stats[attr]
++
++        if cats_attr:
++            self.cats_mgr.SetCategoryAttrs(cat, cats_attr)
++        self.cats_mgr.setCategoryAttrs.connect(self.SetStatistics)
++
++
++    def SetStatistics(self, cat_id, attrs_dict):
++        self.stats_data.statisticsSet.disconnect(self.SetCategory)
++        self.stats_data.GetStatistics(cat_id).SetStatistics(attrs_dict)
++        self.stats_data.statisticsSet.connect(self.SetCategory)
++
++    def AddStatistics(self, cat_id, name, color):
++        self.stats_data.statisticsAdded.disconnect(self.AddCategory)
++        self.stats_data.AddStatistics(cat_id, name, color)
++        self.stats_data.statisticsAdded.connect(self.AddCategory)
++
++    def DeleteStatistics(self, cat_id):
++        self.stats_data.statisticsDeleted.disconnect(self.DeleteCategory)
++        self.stats_data.DeleteStatistics(cat_id)
++        self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
++
++    def GroupSet(self, group):
++        res = RunCommand('i.group',
++                         flags = 'g',
++                         group = group, subgroup = group,
++                         read = True).strip()
++        if res.split('\n')[0]:
++            bands = res.split('\n')
++            self.scatt_mgr.SetData(bands)
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/sc_pl_core.py
+===================================================================
+--- gui/wxpython/scatt_plot/sc_pl_core.py	(revision 0)
++++ gui/wxpython/scatt_plot/sc_pl_core.py	(working copy)
+@@ -0,0 +1,619 @@
++"""!
++ at package scatt_plot.scatt_plot
++
++ at brief Non GUI functions.
++
++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
++
++#TODO
++import time
++
++import numpy as np
++
++from math import sqrt, ceil, floor
++from copy import deepcopy
++
++from grass.script   import core as grass
++from core.gcmd import GException, GError, RunCommand
++
++import grass.script as grass
++
++from core_c import CreateCatRast, ComputeScatts, UpdateCatRast, \
++                   SC_SCATT_DATA, SC_SCATT_CONDITIONS
++
++class Core:
++    def __init__(self):
++        
++        self.an_data = AnalyzedData()
++
++        self.scatts_dt = ScattPlotsData(self.an_data)
++        self.scatt_conds_dt = ScattPlotsCondsData(self.an_data)
++
++        self.cat_rast_updater = CatRastUpdater(self.scatts_dt, self.an_data, self)
++
++    def SetData(self, bands):
++        self.an_data.Create(bands)
++
++        n_bands = len(self.GetBands())
++
++        self.scatts_dt.Create(n_bands)
++        self.scatt_conds_dt.Create(n_bands)
++
++    def AddCategory(self, cat_id):
++        self.scatts_dt.AddCategory(cat_id)
++        return self.scatt_conds_dt.AddCategory(cat_id)
++
++    def DeleteCategory(self, cat_id):
++        self.scatts_dt.DeleteCategory(cat_id)
++        self.scatt_conds_dt.DeleteCategory(cat_id)
++
++    def CleanUp(self):
++        self.scatts_dt.CleanUp()
++        self.scatt_conds_dt.CleanUp()
++
++    def GetBands(self):
++        return self.an_data.GetBands()
++
++    def GetScattsData(self):
++        return self.scatts_dt;
++
++    def GetRegion(self):
++        return self.an_data.GetRegion()
++
++    def GetCatRast(self, cat_id):
++        return self.scatts_dt.GetCatRast(cat_id)
++
++    def AddScattPlot(self, scatt_id):
++    
++        self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++
++        cats_ids = self.scatts_dt.GetCategories()
++        self.ComputeCatsScatts(cats_ids)
++
++
++    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++
++        if cat_id not in self.scatts_dt.GetCategories():
++            raise GException(_("Select category for editing."))
++
++        if self.scatt_conds_dt.AddScattPlot(cat_id, scatt_id) < 0:
++            return False
++
++        arr = self.scatt_conds_dt.GetValuesArr(cat_id, scatt_id)
++
++        for k, v in bbox.iteritems():
++            bbox[k] = self._validExtend(v)
++
++        arr[bbox['btm_y'] : bbox['up_y'], bbox['btm_x'] : bbox['up_x']] = value
++        arr.flush()
++        #del arr
++
++        start_time = time.clock()
++        self.ComputeCatsScatts([cat_id])
++        print "time"
++        print time.clock() - start_time
++        return True
++
++    def ComputeCatsScatts(self, cats_ids):
++
++        requested_dt = {}
++        requested_dt_conds = {}
++
++        for c in cats_ids:
++            requested_dt_conds[c] = self.scatt_conds_dt.GetCatScatts(c)
++            requested_dt[c] = self.scatts_dt.GetCatScatts(c)
++
++        scatt_conds = self.scatt_conds_dt.GetData(requested_dt_conds)
++        scatts = self.scatts_dt.GetData(requested_dt)
++
++        bands = self.an_data.GetBands()
++
++        cats_rasts = self.scatts_dt.GetCatsRasts()
++        cats_rasts_conds = self.scatts_dt.GetCatsRastsConds()
++
++        returncode, scatts = ComputeScatts(self.an_data.GetRegion(), scatt_conds, bands,
++                                           len(self.GetBands()), scatts, cats_rasts_conds, cats_rasts)
++        
++        #self.scatts_dt.SetData(scatts)
++
++    def CatRastUpdater(self):
++        return self.cat_rast_updater
++        
++    def _validExtend(self, val):
++        #TODO do it general
++        if  val > 255:
++            val = 255
++        elif val < 0:
++            val = 0
++
++        return val
++
++class CatRastUpdater:
++
++    def __init__(self, scatts_dt, an_data, core):
++        self.scatts_dt = scatts_dt
++        self.an_data = an_data # TODO may be confusing
++        self.core = core
++        self.vectMap = None
++
++    def SetVectMap(self, vectMap):
++        self.vectMap = vectMap
++
++    def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
++        #TODO possible optimization - bbox only of vertex and its two neighbours
++
++        bboxs = old_bboxs + new_bboxs
++        areas_cats = old_areas_cats + new_areas_cats 
++
++        updated_cats = []
++
++        for i in range(len(areas_cats)):
++            self._updateCatRast(bboxs[i], areas_cats[i], updated_cats)
++        
++        return updated_cats
++
++    def _updateCatRast(self, bbox, areas_cats, updated_cats):
++
++        rasterized_cats = []
++        for c in range(len(areas_cats)):
++
++            if not areas_cats[c]:
++                continue
++
++            layer = areas_cats[c].keys()[0]
++            cat =  areas_cats[c][layer][0]
++
++            if cat in rasterized_cats:
++                continue
++
++            rasterized_cats.append(cat)
++            updated_cats.append(cat)
++
++            grass_region = self._create_grass_region_env(bbox)
++
++            #TODO hack
++            patch_rast = "temp_scatt_patch"
++            self._rasterize(grass_region, layer, cat, patch_rast)
++
++            region = self.an_data.GetRegion()
++            UpdateCatRast(patch_rast, region, self.scatts_dt.GetCatRastCond(cat))
++            
++            RunCommand("g.remove",
++                       rast = patch_rast)#,
++
++    def _rasterize(self, grass_region, layer, cat, out_rast):
++
++        #TODO different thread may be problem when user edits map
++        ret, text, msg = RunCommand("v.build",
++                                      map = self.vectMap,
++                                      getErrorMsg = True,
++                                      read = True)#,
++
++        #TODO thread problem with env variable remove it!!!!
++        environs = os.environ.copy()
++        environs["GRASS_REGION"] = grass_region["GRASS_REGION"]
++
++        ret, text, msg = RunCommand("v.to.rast",
++                                    input = self.vectMap,
++                                    use = "cat",
++                                    layer = str(layer),
++                                    cat = str(cat),
++                                    output = out_rast,
++                                    getErrorMsg = True,
++                                    read = True,
++                                    overwrite = True,
++                                    env = environs)
++    def _create_grass_region_env(self, bbox):
++
++        region = self.an_data.GetRegion()
++        new_region = {}
++
++        if bbox["maxy"] <= region["s"]:
++            return 0
++        elif bbox["maxy"] >= region["n"]:
++            new_region["n"] = bbox["maxy"]
++        else:
++            new_region["n"] = ceil((bbox["maxy"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++
++        if bbox["miny"] >= region["n"]:
++            return 0
++        elif bbox["miny"] <= region["s"]:
++            new_region["s"] = bbox["miny"]
++        else:
++            new_region["s"] = floor((bbox["miny"] - region["s"]) / region["nsres"]) * region["nsres"] + region["s"]
++
++        if bbox["maxx"] <= region["w"]:
++            return 0
++        elif bbox["maxx"] >= region["e"]:
++            new_region["e"] = bbox["maxx"]
++        else:
++            new_region["e"] = ceil((bbox["maxx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++
++        if bbox["minx"] >= region["e"]:
++            return 0
++        elif bbox["minx"] <= region["w"]:
++            new_region["w"] = bbox["minx"]
++        else:
++            new_region["w"] = floor((bbox["minx"] - region["w"]) / region["ewres"]) * region["ewres"] + region["w"]
++
++        #TODO check regions resolutin
++        new_region["nsres"] = region["nsres"]
++        new_region["ewres"] = region["ewres"]
++
++        return {"GRASS_REGION" :  grass.region_env(**new_region)}
++
++class AnalyzedData:
++
++    def __init__(self):
++        
++        self.bands = []
++        self.bands_info = {}
++
++        self.region = None
++
++    def GetRegion(self):
++        return self.region
++
++    def Create(self, bands):
++
++        self.bands = bands
++        self.region = None
++
++        ret, region, msg = RunCommand("g.region",
++                                      flags = "gp",
++                                      getErrorMsg = True,
++                                      read = True)
++
++        if  ret != 0:
++            raise GException("g.region failed:\n%s" % msg)
++
++
++        self.bands_info = {}
++        for b in bands:
++            self.bands_info[b] = self._getRasterInfo(b)
++            if self.bands_info[b]["datatype"] != "CELL":
++                raise GException(_("Raster <%s> is not <CELL> type.") % (b))
++            #TODO size of raster check
++
++        self.region = self._parseRegion(region)
++
++    def _getRasterInfo(self, rast):
++        """
++        """
++        ret, out, msg = RunCommand("r.info",
++                                    map = rast,
++                                    flags = "rg",
++                                    getErrorMsg = True,
++                                    read = True)
++
++        if  ret != 0:
++            raise GException("r.info failed:\n%s" % msg)
++
++        out = out.split("\n")
++        raster_info = {} 
++
++        for b in out:
++            if not b.strip():
++                continue
++            k, v = b.split("=")
++            if k == "datatype":
++                pass
++            elif k in ['rows', 'cols', 'cells', 'min', 'max']:
++                v = int(v)
++            else:
++                v = float(v)
++
++            raster_info[k] = v
++
++        return raster_info
++
++    def GetBands(self):
++        return self.bands
++
++    def GetBandInfo(self, band_id):
++        band = self.bands[band_id]
++        return self.bands_info[band]
++
++    def _parseRegion(self, region_str):
++
++        region = {}
++        region_str = region_str.splitlines()
++
++        for param in region_str:
++            k, v = param.split("=")
++            if k in ["rows", "cols", "cells"]:
++                v = int(v)
++            else:
++                v = float(v)
++            region[k] = v
++
++        return region
++
++class ScattPlotsCondsData:
++
++    def __init__(self, an_data):
++
++        self.an_data = an_data
++
++        #TODO
++        self.max_n_cats = 10
++    
++        self.dtype = 'uint8'
++        self.type = 1;
++        self.CleanUp()
++
++    def CleanUp(self):
++    
++        self.cats = {}
++
++        self.n_scatts = -1
++        self.n_bands = -1
++
++        for cat_id in self.cats.keys():
++            self.DeleteCategory(cat_id)
++
++    def Create(self, n_bands):
++
++        self.CleanUp()
++
++        self.n_scatts =  (n_bands - 1) * n_bands / 2;
++        self.n_bands = n_bands
++
++        self.AddCategory(cat_id = 0)
++
++    def AddCategory(self, cat_id):
++
++        if cat_id not in self.cats.keys():
++            self.cats[cat_id] = {}
++            return cat_id
++        return -1
++
++    def DeleteCategory(self, cat_id):
++
++        if cat_id not in self.cats.keys():
++            return False
++
++        for scatt in self.cats[cat_id].itervalues():
++            del scatt['np_vals']
++
++        del self.cats[cat_id]
++
++        return True
++
++    def GetCategories(self):
++        return self.cats.keys()
++
++    def GetCatScatts(self, cat_id):
++
++        if not self.cats.has_key(cat_id):
++            return False
++
++        return self.cats[cat_id].keys()
++
++
++    def AddScattPlot(self, cat_id, scatt_id):
++
++        if not self.cats.has_key(cat_id):
++            return -1
++
++        if self.cats[cat_id].has_key(scatt_id):
++            return 0
++
++        b_i = self.GetBandsInfo(scatt_id)
++
++        shape = (b_i['b2']['max'] - b_i['b2']['min'] + 1, b_i['b1']['max'] - b_i['b1']['min'] + 1)
++
++        np_vals = np.memmap(grass.tempfile(), dtype=self.dtype, mode='w+', shape = shape)
++        np_vals.flush()
++
++        self.cats[cat_id][scatt_id] = {
++                                        'np_vals' : np_vals
++                                      }
++
++        return 1
++
++    def GetBandsInfo(self, scatt_id):
++        b1, b2 = idScattToidBands(scatt_id, len(self.an_data.GetBands()))
++
++        b1_info = self.an_data.GetBandInfo(b1)
++        b2_info = self.an_data.GetBandInfo(b2)
++
++        bands_info = {'b1' : b1_info,
++                      'b2' : b2_info}
++
++        return bands_info
++
++    def DeleScattPlot(self, cat_id, scatt_id):
++
++        if not self.cats.has_key(cat_id):
++            return False
++
++        if not self.cats[cat_id].has_key(scatt_id):
++            return False
++
++        del self.cats[cat_id][scatt_id]
++        return True
++
++    def GetValuesArr(self, cat_id, scatt_id):
++
++        if not self.cats.has_key(cat_id):
++            return None
++
++        if not self.cats[cat_id].has_key(scatt_id):
++            return None
++
++        return self.cats[cat_id][scatt_id]['np_vals']
++
++    def GetData(self, requested_dt):
++        
++        cats = {}
++        for cat_id, scatt_ids in requested_dt.iteritems():
++            if not cats.has_key(cat_id):
++                cats[cat_id] = {}
++            for scatt_id in scatt_ids:
++                # if key is missing condition is always True (full scatter plor is computed)
++                if self.cats[cat_id].has_key(scatt_id):
++                    cats[cat_id][scatt_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
++                                              'bands_info' : self.GetBandsInfo(scatt_id)}
++                        
++        return cats
++
++    def SetData(self, cats):
++        
++        for cat_id, scatt_ids in cats.iteritems():            
++            for scatt_id in scatt_ids:
++                # if key is missing condition is always True (full scatter plor is computed)
++                if self.cats[cat_id].has_key(scatt_id):
++                    self.cats[cat_id][scatt_id]['np_vals'] = cats[cat_id][scatt_id]['np_vals']
++                   
++class ScattPlotsData(ScattPlotsCondsData):
++
++    def __init__(self, an_data):
++
++        self.cats_rasts = {}
++        self.cats_rasts_conds = {}    
++        self.scatts_ids = []    
++
++        ScattPlotsCondsData.__init__(self, an_data)
++
++        self.dtype = 'uint32'
++
++        #TODO
++        self.type = 0
++
++    def AddCategory(self, cat_id):
++        cat_id = ScattPlotsCondsData.AddCategory(self, cat_id)
++        if cat_id < 0:
++            return cat_id
++
++        for scatt_id in self.scatts_ids:
++            ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
++
++        if cat_id == 0:
++            self.cats_rasts_conds[cat_id] = None
++            self.cats_rasts[cat_id] = None
++        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])   
++
++        return cat_id
++
++    def DeleteCategory(self, cat_id):
++
++        ScattPlotsCondsData.DeleteCategory(self, cat_id)
++
++        grass.try_remove(self.cats_rasts_conds[cat_id])
++        del self.cats_rasts_conds[cat_id]
++
++        grass.try_remove(self.cats_rasts[cat_id])
++        del self.cats_rasts[cat_id]
++
++        return True
++
++    def AddScattPlot(self, scatt_id):
++        
++        if scatt_id in self.scatts_ids:
++            return False
++
++        self.scatts_ids.append(scatt_id)
++        for cat_id in self.cats.iterkeys():
++                ScattPlotsCondsData.AddScattPlot(self, cat_id, scatt_id)
++
++        return True
++
++    def DeleteScatterPlot(self, scatt_id):
++        
++        if scatt_id not in self.scatts_ids:
++            return False
++
++        self.scatts_ids.remove(scatt_id)
++
++        for cat_id in self.cats.iterkeys():
++                ScattPlotsCondsData.DeleteScattPlot(self, cat_id, scatt_id)
++
++        return True
++
++    def GetScatt(self, scatt_id):
++        if scatt_id not in self.scatts_ids:
++            return False
++
++        scatts = {}
++        for cat_id in self.cats.iterkeys():
++            scatts[cat_id] = {'np_vals' : self.cats[cat_id][scatt_id]['np_vals'],
++                              'bands_info' : self.GetBandsInfo(scatt_id)}
++        return scatts
++
++    def CleanUp(self):
++
++        ScattPlotsCondsData.CleanUp(self)        
++        for tmp in self.cats_rasts_conds:
++            grass.try_remove(tmp) 
++        for tmp in self.cats_rasts:
++            grass.try_remove(tmp) 
++
++        self.cats_rasts = {}
++        self.cats_rasts_conds = {}
++
++
++    def GetCatRast(self, cat_id):
++        return self.cats_rasts[cat_id]
++
++    def GetCatRastCond(self, cat_id):
++        return self.cats_rasts_conds[cat_id]
++
++    def GetCatsRastsConds(self):
++        max_cat_id = max(self.cats_rasts_conds.keys())
++
++        cats_rasts_conds = [''] * (max_cat_id + 1)
++        for i_cat_id, i_rast in self.cats_rasts_conds.iteritems():
++            cats_rasts_conds[i_cat_id] = i_rast
++
++        return cats_rasts_conds
++
++    def GetCatsRasts(self):
++        max_cat_id = max(self.cats_rasts.keys())
++
++        cats_rasts = [''] * (max_cat_id + 1)
++        for i_cat_id, i_rast in self.cats_rasts.iteritems():
++            cats_rasts[i_cat_id] = i_rast
++
++        return cats_rasts
++
++#TODO move to utils?
++def idScattToidBands(scatt_id, n_bands):
++ 
++    n_b1 = n_bands - 1
++
++    band_1 = (int) ((2 * n_b1 + 1 - sqrt(((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
++
++    return band_1, band_2
++
++
++def idBandsToidScatt(band_1_id, band_2_id, n_bands):
++
++    if band_2_id <  band_1_id:
++        tmp = band_1
++        band_1_id = band_2_id
++        band_2_id = tmp
++
++    n_b1 = n_bands - 1
++
++    scatt_id = (band_1_id * (2 * n_b1 + 1) - band_1_id * band_1_id) / 2 + band_2_id - band_1_id - 1
++
++    return scatt_id
++
+Index: gui/wxpython/Makefile
+===================================================================
+--- 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/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")
++
+         # 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)
+         
++        self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
+         return True
+ 
+     def StopEditing(self):
 Index: gui/wxpython/vdigit/wxdigit.py
 ===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57336)
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57437)
 +++ gui/wxpython/vdigit/wxdigit.py	(working copy)
 @@ -17,7 +17,7 @@
  (and NumPy would be an excellent candidate for acceleration via
@@ -2756,12 +3129,14 @@
  from core.gcmd        import GError
  from core.debug       import Debug
  from core.settings    import UserSettings
-@@ -176,7 +178,17 @@
+@@ -176,7 +178,19 @@
          
          if self.poMapInfo:
              self.InitCats()
 -        
 +
++        self.use_signals = False
++
 +        #TODO signal for errors?
 +        self.featureAdded = Signal('IVDigit.featureAdded')
 +        self.areasDeleted = Signal('IVDigit.areasDeleted')
@@ -2775,7 +3150,7 @@
      def __del__(self):
          Debug.msg(1, "IVDigit.__del__()")
          Vect_destroy_line_struct(self.poPoints)
-@@ -394,7 +406,6 @@
+@@ -394,7 +408,6 @@
          
          @return tuple (number of added features, feature ids)
          """
@@ -2783,7 +3158,7 @@
          layer = self._getNewFeaturesLayer()
          cat = self._getNewFeaturesCat()
          
-@@ -419,10 +430,14 @@
+@@ -419,10 +432,14 @@
              return (-1, None)
          
          self.toolbar.EnableUndo()
@@ -2795,19 +3170,19 @@
 +        ret = self._addFeature(vtype, points, layer, cat,
 +                               self._getSnapMode(), self._display.GetThreshold())
 +        if ret[0] > -1:
-+            self.featureAdded.emit(new_geom = points, cat = {layer : [cat]})
++            self.featureAdded.emit(new_bboxs = [self._createBbox(points)], new_areas_cats = [[{layer : [cat]}, None]])
 +
 +        return ret
 +
      def DeleteSelectedLines(self):
          """!Delete selected features
  
-@@ -434,16 +449,25 @@
+@@ -434,16 +451,27 @@
          # colect categories for delete if requested
          deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
          catDict = dict()
 +
-+        old_geoms = []
++        old_bboxs = []
 +        old_areas_cats = []
          if deleteRec:
              for i in self._display.selected['ids']:
@@ -2815,8 +3190,10 @@
                  if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
                      self._error.ReadLine(i)
                  
-+                old_geoms.append(self._getGeom(i))
-+                old_areas_cats.append(self._getLineAreasCategories(i))
++                ret = self._getLineAreaBboxCats(i)
++                if ret:
++                    old_bboxs += ret[0]
++                    old_areas_cats += ret[1]
 +                
                  cats = self.poCats.contents
 -                for j in range(cats.n_cats):
@@ -2832,17 +3209,17 @@
          
          poList = self._display.GetSelectedIList()
          nlines = Vedit_delete_lines(self.poMapInfo, poList)
-@@ -456,7 +480,8 @@
+@@ -456,7 +484,8 @@
                  self._deleteRecords(cats)
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
-+            self.featuresDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
++            self.featuresDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)
 +
          return nlines
              
      def _deleteRecords(self, cats):
-@@ -512,22 +537,123 @@
+@@ -512,22 +541,171 @@
  
          @return number of deleted 
          """
@@ -2853,7 +3230,7 @@
          cList  = poList.contents
          
          nareas = 0
-+        old_geoms = []
++        old_bboxs = []
 +        old_areas_cats = []
 +
          for i in range(cList.n_values):
@@ -2864,8 +3241,8 @@
 +
 +            area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
 +            if area > 0: 
-+                geoms, cats = self._getaAreaGeomsCats(area)
-+                old_geoms += geoms
++                bbox, cats = self._getaAreaBboxCats(area)
++                old_bboxs += bbox
 +                old_areas_cats += cats
 +
              nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
@@ -2873,13 +3250,32 @@
          if nareas > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
-+            self.areasDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)        
++            self.areasDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)        
 +
 +        return nareas
 +   
++    def _getLineAreaBboxCats(self, ln_id):
++        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
 +
-+    def _getaAreaGeomsCats(self, area):
++        if ltype == GV_CENTROID:
++            #TODO centroid opttimization, can be adited also its area -> it will appear two times in new_ lists
++            return self._getCentroidAreaBboxCats(ln_id)
++        else: 
++            return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)]
 +
++
++    def _getCentroidAreaBboxCats(self, centroid):
++        if not Vect_line_alive(self.poMapInfo, centroid):
++            return None
++
++        area = Vect_get_centroid_area(self.poMapInfo, centroid)  
++        if area > 0:
++            return self._getaAreaBboxCats(area)
++        else:
++            return None
++
++    def _getaAreaBboxCats(self, area):
++
 +        po_b_list = Vect_new_list()
 +        Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
 +        b_list = po_b_list.contents
@@ -2888,11 +3284,11 @@
 +        areas_cats = []
 +
 +        if b_list.n_values > 0:
-+            for i_line in  range(b_list.n_values):
++            for i_line in range(b_list.n_values):
 +
 +                line = b_list.value[i_line];
 +
-+                geoms.append(self._getGeom(abs(line)))
++                geoms.append(self._getBbox(abs(line)))
 +                areas_cats.append(self._getLineAreasCategories(abs(line)))
          
 -        return nareas
@@ -2901,6 +3297,8 @@
 +        return geoms, areas_cats
 +
 +    def _getLineAreasCategories(self, ln_id):
++        if not Vect_line_alive (self.poMapInfo, ln_id):
++            return []
 +
 +        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
 +        if ltype != GV_BOUNDARY:
@@ -2926,7 +3324,9 @@
 +        return cats
 +
 +    def _getCategories(self, ln_id):
-+        
++        if not Vect_line_alive (self.poMapInfo, ln_id):
++            return none
++
 +        poCats = Vect_new_cats_struct()
 +        if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
 +            Vect_destroy_cats_struct(poCats)
@@ -2944,17 +3344,42 @@
 +        Vect_destroy_cats_struct(poCats)
 +        return cats
 +
-+    def _getGeom(self, ln_id):
++    def _getBbox(self, ln_id):
++        if not Vect_line_alive (self.poMapInfo, ln_id):
++            return None
 +
 +        poPoints = Vect_new_line_struct()
 +        if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
 +            Vect_destroy_line_struct(poPoints)
-+            return None
++            return []
 +
 +        geom = self._convertGeom(poPoints)
++        bbox = self._createBbox(geom)
 +        Vect_destroy_line_struct(poPoints)
-+        return geom
++        return bbox
 +
++    def _createBbox(self, points):
++
++        bbox = {}
++        for pt in points:
++            if not bbox.has_key('maxy'):
++                bbox['maxy'] = pt[1]
++                bbox['miny'] = pt[1]
++                bbox['maxx'] = pt[0]
++                bbox['minx'] = pt[0]
++                continue
++                
++            if   bbox['maxy'] < pt[1]:
++                bbox['maxy'] = pt[1]
++            elif bbox['miny'] > pt[1]:
++                bbox['miny'] = pt[1]
++                
++            if   bbox['maxx'] < pt[0]:
++                bbox['maxx'] = pt[0]
++            elif bbox['minx'] > pt[0]:
++                bbox['minx'] = pt[0]
++        return bbox
++
 +    def _convertGeom(self, poPoints):
 +
 +        Points = poPoints.contents
@@ -2968,7 +3393,7 @@
      def MoveSelectedLines(self, move):
          """!Move selected features
  
-@@ -536,16 +662,39 @@
+@@ -536,16 +714,43 @@
          if not self._checkMap():
              return -1
          
@@ -2981,48 +3406,53 @@
          
          poList = self._display.GetSelectedIList()
 +
-+        old_geoms = []
++        old_bboxs = []
 +        old_areas_cats = []
 +        for sel_id in self._display.selected['ids']:
-+            old_geoms.append(self._getGeom(sel_id))
-+            old_areas_cats.append(self._getLineAreasCategories(sel_id))
-+
-+        poNewIds = Vect_new_list()
++            ret = self._getLineAreaBboxCats(sel_id)
++            if ret:
++                old_bboxs += ret[0]
++                old_areas_cats += ret[1]
++        
++        Vect_set_updated(self.poMapInfo, 1)
++        n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
          nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
                                    poList,
                                    move[0], move[1], 0,
--                                  snap, thresh)
-+                                  snap, thresh, poNewIds)
+                                   snap, thresh)
 +
          Vect_destroy_list(poList)
-         
-+        cList = poNewIds.contents
+-        
 +
 +        if nlines > 0:
++            new_bboxs = []
 +            new_areas_cats = []
-+            for i in range(cList.n_values):
-+                new_id = cList.value[i]
-+                new_areas_cats.append(self._getLineAreasCategories(new_id))
++            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++            for i in range(n_up_lines_old, n_up_lines):
++                new_id = Vect_get_updated_line(self.poMapInfo, i)
++                ret = self._getLineAreaBboxCats(new_id)
++                if ret:
++                    new_bboxs += ret[0]
++                    new_areas_cats += ret[1]
 +
-+        Vect_destroy_list(poNewIds)
-+
          if nlines > 0 and self._settings['breakLines']:
              for i in range(1, nlines):
                  self._breakLineAtIntersection(nlines + i, None, changeset)
-@@ -553,7 +702,11 @@
+@@ -553,7 +758,12 @@
          if nlines > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
-+ 
-+            self.featuresMoved.emit(move = move, 
-+                                    old_geoms = old_geoms, 
++            
++            self.featuresMoved.emit(new_bboxs = new_bboxs,
++                                    old_bboxs = old_bboxs, 
 +                                    old_areas_cats = old_areas_cats, 
 +                                    new_areas_cats = new_areas_cats)
++
          return nlines
  
      def MoveSelectedVertex(self, point, move):
-@@ -571,20 +724,33 @@
+@@ -571,12 +781,19 @@
          
          if len(self._display.selected['ids']) != 1:
              return -1
@@ -3032,8 +3462,8 @@
 +        poList = self._display.GetSelectedIList()
 +
 +        cList = poList.contents
-+        old_geom = self._getGeom(cList.value[0])
-+        old_areas_cats = self._getLineAreasCategories(cList.value[0])
++        old_bboxs = [self._getBbox(cList.value[0])]
++        old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
 +
          Vect_reset_line(self.poPoints)
          Vect_append_point(self.poPoints, point[0], point[1], 0.0)
@@ -3041,101 +3471,112 @@
 -        # move only first found vertex in bbox 
 -        poList = self._display.GetSelectedIList()
 +
-+        poNewIds = Vect_new_list()
++        Vect_set_updated(self.poMapInfo, 1)
++        n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
          moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
                                    poList, self.poPoints,
                                    self._display.GetThreshold(type = 'selectThresh'),
-                                   self._display.GetThreshold(),
+@@ -584,7 +801,17 @@
                                    move[0], move[1], 0.0,
--                                  1, self._getSnapMode())
-+                                  1, self._getSnapMode(), poNewIds)
+                                   1, self._getSnapMode())
          Vect_destroy_list(poList)
 -        
 +
-+        new_id = poNewIds.contents.value[0]
-+        Vect_destroy_list(poNewIds)
++        n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
 +
-+        if new_id > -1:
-+            new_geom = self._getGeom(new_id)
-+            new_areas_cats = self._getLineAreasCategories(new_id)
++        if moved > 0:
++            new_bboxs = []
++            new_areas_cats = []
++            for i in range(n_up_lines_old, n_up_lines):
++                new_id = Vect_get_updated_line(self.poMapInfo, i)
++                new_bboxs.append(self._getBbox(new_id))
++                new_areas_cats.append(self._getLineAreasCategories(new_id))
 +
          if moved > 0 and self._settings['breakLines']:
              self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
                                            None)
-@@ -592,7 +758,13 @@
+@@ -592,7 +819,12 @@
          if moved > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
 +
-+        if new_id > -1:
-+            self.vertexMoved.emit(new_geom = new_geom,  
++            self.vertexMoved.emit(new_bboxs = new_bboxs,  
 +                                  new_areas_cats = new_areas_cats, 
 +                                  old_areas_cats = old_areas_cats, 
-+                                  old_geom = old_geom)
++                                  old_bboxs = old_bboxs)
 +
          return moved
  
      def AddVertex(self, coords):
-@@ -681,6 +853,9 @@
+@@ -681,6 +913,9 @@
              self._error.ReadLine(line)
              return -1
          
-+        old_geom = self._getGeom(line)
-+        old_areas_cats = self._getLineAreasCategories(line)
++        old_bboxs = [self._getBbox(line)]
++        old_areas_cats = [self._getLineAreasCategories(line)]
 +
          # build feature geometry
          Vect_reset_line(self.poPoints)
          for p in coords:
-@@ -703,7 +878,15 @@
+@@ -696,6 +931,9 @@
+         
+         newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
+                                     self.poPoints, self.poCats)
++        if newline > 0:
++            new_geom = [self._getBbox(newline)]
++            new_areas_cats = [self._getLineAreasCategories(newline)]
+         
+         if newline > 0 and self._settings['breakLines']:
+             self._breakLineAtIntersection(newline, None)
+@@ -703,7 +941,12 @@
          if newline > 0:
              self._addChangeset()
              self.toolbar.EnableUndo()
 -        
-+
-+            new_geom = self._getGeom(newline)
-+            new_areas_cats = self._getLineAreasCategories(newline)
 +    
-+            self.lineEdited.emit(old_geom = old_geom, 
++            self.lineEdited.emit(old_bboxs = old_bboxs, 
 +                                 old_areas_cats = old_areas_cats, 
-+                                 new_geom = new_geom, 
++                                 new_bboxs = new_bboxs, 
 +                                 new_areas_cats = new_areas_cats)
 +
          return newline
  
      def FlipLine(self):
-@@ -1510,26 +1693,49 @@
+@@ -1510,26 +1753,52 @@
              return 0
          
          poList  = self._display.GetSelectedIList()
 +        cList = poList.contents
 +        
-+        old_geom = self._getGeom(cList.value[0])
-+        old_areas_cats = self._getLineAreasCategories(cList.value[0])
++        old_bboxs = [self._getBbox(cList.value[0])]
++        old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
 +
          Vect_reset_line(self.poPoints)
          Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
          
          thresh = self._display.GetThreshold(type = 'selectThresh')
          
-+        poNewIds = Vect_new_list()
-+
++        Vect_set_updated(self.poMapInfo, 1)
++        n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
          if add:
              ret = Vedit_add_vertex(self.poMapInfo, poList,
--                                   self.poPoints, thresh)
-+                                   self.poPoints, thresh, poNewIds)
+                                    self.poPoints, thresh)
          else:
              ret = Vedit_remove_vertex(self.poMapInfo, poList,
--                                      self.poPoints, thresh)
-+                                      self.poPoints, thresh, poNewIds)
+                                       self.poPoints, thresh)
 +
-+        new_id = poNewIds.contents.value[0]
-+        Vect_destroy_list(poNewIds)
          Vect_destroy_list(poList)
 +
-+        if new_id > -1:
-+            new_geom = self._getGeom(new_id)
-+            new_areas_cats = self._getLineAreasCategories(new_id)
++        if ret > 0:
++            new_bboxs = []
++            new_areas_cats = []
++
++            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++            for i in range(n_up_lines_old, n_up_lines):
++                new_id = Vect_get_updated_line(self.poMapInfo, i)
++                new_areas_cats.append(self._getLineAreasCategories(new_id))
++                new_bboxs.append(self._getBbox(new_id))
          
          if not add and ret > 0 and self._settings['breakLines']:
              self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
@@ -3146,74 +3587,494 @@
              self._addChangeset()
 -                
 +
-+        if new_id > -1:
 +            if add:
-+                self.vertexAdded.emit(old_geom = old_geom, new_geom = new_geom)
++                self.vertexAdded.emit(old_bboxs = old_bboxs, new_bboxs = new_bboxs)
 +            else:
-+                self.vertexRemoved.emit(old_geom = old_geom, 
-+                                        new_geom = new_geom,
++                self.vertexRemoved.emit(old_bboxs = old_bboxs, 
++                                        new_bboxs = new_bboxs,
 +                                        old_areas_cats = old_areas_cats,
 +                                        new_areas_cats = new_areas_cats)
 +
          return 1
      
      def GetLineCats(self, line):
-Index: gui/wxpython/vdigit/toolbars.py
+Index: gui/wxpython/mapdisp/toolbars.py
 ===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57336)
-+++ gui/wxpython/vdigit/toolbars.py	(working copy)
-@@ -17,6 +17,7 @@
- import wx
+--- 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)))
+         
+     def OnDecoration(self, event):
+         """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py	(revision 57437)
++++ gui/wxpython/mapdisp/frame.py	(working copy)
+@@ -226,6 +226,7 @@
+         #
+         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']
  
- 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")
++    def OnScatterplot2(self, event):
++        """!Init interactive scatterplot tools
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
 +
-         # 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)
-@@ -820,6 +823,7 @@
-             alpha = int(opacity * 255)
-             self.digit.GetDisplay().UpdateSettings(alpha = alpha)
-         
-+        self.editingStarted.emit(vectMap = mapLayer.GetName())
-         return True
- 
-     def StopEditing(self):
-Index: gui/wxpython/Makefile
++        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: lib/imagery/scatt_sccats.c
 ===================================================================
---- gui/wxpython/Makefile	(revision 57336)
-+++ 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 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 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)
- 
+--- lib/imagery/scatt_sccats.c	(revision 0)
++++ lib/imagery/scatt_sccats.c	(working copy)
+@@ -0,0 +1,421 @@
++/*!
++   \file lib/imagery/scatt_cat_rast.c
++
++   \brief Imagery library - functions for manipulation with scatter plot structs.
++
++   Copyright (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.
++
++   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
++
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++
++/*!
++   \brief Compute band ids from scatter plot id.
++
++   \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
++ */
++static void id_scatt_to_bands(const int scatt_id, const int n_bands, int * band_1, int * band_2)
++{   
++    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);
++
++    * band_2 = scatt_id - ((* band_1) * (2 * n_b1 + 1) - (* band_1) * (* band_1)) / 2 + (* band_1) + 1;
++
++    return;
++}
++
++
++/*!
++   \brief Compute scatter plot id from band ids.
++
++   \param n_bands number of bands
++   \param band_1 id of band1
++   \param band_2 id of band2
++   \param [out] scatt_id scatter plot id
++ */
++static void bands_to_id_scatt(const int band_1, const int band_2, 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;
++
++    return;
++}
++
++/*!
++   \brief Initialize structury for soring scatter plots data.
++
++   \param cats pointer to scCats struct 
++   \param n_bands number of bands
++   \param type SC_SCATT_DATA - stores scatter plots 
++   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
++ */
++void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
++{
++    int i_cat;
++
++    cats->type = type;
++
++    cats->n_cats = 100;
++    cats->n_a_cats = 0;
++
++    cats->n_bands = n_bands;
++    cats->n_scatts = (n_bands - 1) * n_bands / 2;
++
++    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
++    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
++
++    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
++    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
++
++    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
++        cats->cats_idxs[i_cat] = -1;
++
++    return;
++}
++
++/*!
++   \brief Free date of struct scCats, the structure itself remains alocated.   .
++
++   \param cats pointer to existing scCats struct
++ */
++void I_sc_free_cats(struct scCats * cats)
++{
++    int i_cat;
++
++    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
++    {        
++        if(cats->cats_arr[i_cat])
++        {   
++            G_free(cats->cats_arr[i_cat]->scatt_idxs);
++            G_free(cats->cats_arr[i_cat]->scatts_bands);
++            G_free(cats->cats_arr[i_cat]->scatts_arr);
++            G_free(cats->cats_arr[i_cat]);
++        }
++    }
++
++    G_free(cats->cats_ids);
++    G_free(cats->cats_idxs);
++    G_free(cats->cats_arr);
++
++    cats->n_cats = 0;
++    cats->n_a_cats = 0;
++    cats->n_bands = 0;
++    cats->n_scatts = 0;
++    cats->type = -1;
++
++    return;
++}
++
++#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 
++ */
++int I_sc_add_cat(struct scCats * cats, int cat_id)
++{
++    int i_scatt;
++    int n_a_cats = cats->n_a_cats;
++
++    if(cat_id < 0 || cat_id > cats->n_cats)
++        return -1;
++
++    if(cat_id >= cats->n_cats)
++        return -2;
++
++    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;
++    
++    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
++
++    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
++    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
++    
++    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
++
++    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
++     
++    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
++    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
++        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
++    
++    ++cats->n_a_cats;
++
++    return 0;
++}
++
++#if 0
++int I_sc_delete_cat(struct scCats * cats, int cat_id)
++{
++    int cat_idx, i_cat;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
++    G_free(cats->cats_arr[cat_idx]->scatts_bands);
++    G_free(cats->cats_arr[cat_idx]->scatts_arr);
++    G_free(cats->cats_arr[cat_idx]);
++
++    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
++    {
++        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
++        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
++    }
++    cats->cats_idxs[cat_id] = -1; 
++
++    --cats->n_a_cats;
++    
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data .
++    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
++
++   \param cats pointer to scCats struct
++   \param cat_id id number of category.
++   \param scatt_id id number of scatter plot.
++
++   \return  0 on success
++   \return -1 on failure
++ */
++int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int band_1, band_2, cat_idx, n_a_scatts;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] >= 0)
++        return -1;
++
++    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
++        return -1;
++
++    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
++        return -1;
++
++    n_a_scatts = scatts->n_a_scatts;
++
++    scatts->scatt_idxs[scatt_id] = n_a_scatts;
++
++    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;
++
++    scatts->scatts_arr[n_a_scatts] = scatt_data;
++    ++scatts->n_a_scatts;
++
++    return 0;
++}
++
++#if 0
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 && cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    scatt_data = scatts->scatts_arr[scatt_idx];
++
++    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
++    {
++        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
++        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
++        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
++    }
++    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
++
++    scatts->scatt_idxs[scatt_id] = -1;
++
++    scatt_data = scatts->scatts_arr[scatt_id];
++    scatts->n_a_scatts--;
++
++    return 0;
++}
++
++int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
++{
++    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
++    int cat_idx, scatt_idx, ret;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++    
++    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
++
++    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
++
++    return 0;
++}
++#endif
++
++/*!
++   \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)
++{
++    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)
++            scatt_data->scatt_vals_arr = (unsigned int *) data;
++        else {
++            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
++            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
++        }
++        scatt_data->b_conds_arr = NULL;
++    }
++    else if(type == SC_SCATT_CONDITIONS)
++    {
++        if(data)
++            scatt_data->b_conds_arr = (unsigned char *) data;
++        else {
++            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
++            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
++        }
++        scatt_data->scatt_vals_arr = NULL;
++    }
++
++    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)
++{
++
++    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
++    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
++
++    return;
++}
++s
++void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
++{
++    if(!scatt_data->b_conds_arr)
++        return scatt_data->b_conds_arr;
++    else if(!scatt_data->scatt_vals_arr)
++        return scatt_data->scatt_vals_arr;
++
++    return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
++{
++    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
++        return -1;
++
++    if(scatt_data->b_conds_arr)
++        scatt_data->b_conds_arr[val_idx] = val;
++    else if(scatt_data->scatt_vals_arr)
++        scatt_data->scatt_vals_arr[val_idx] = val;
++    else
++        return -1;
++
++    return 0;
++}
++#endif
 Index: lib/imagery/scatt.c
 ===================================================================
 --- lib/imagery/scatt.c	(revision 0)
 +++ lib/imagery/scatt.c	(working copy)
-@@ -0,0 +1,610 @@
+@@ -0,0 +1,696 @@
 +/*!
 +   \file lib/imagery/scatt.c
 +
@@ -3239,14 +4100,24 @@
 +#include <string.h>
 +
 +
-+static const int CAT_RAST_SCATT_SEL = 2;
-+static const int CAT_RAST_RAST_SEL = 1;
-+static const int  CAT_RAST_NULL = 0;
++/*!
++   \brief Create pgm header.
 +
++   Scatter plot internally generates pgm files. These pns has header in format created by this function.
++    
++   \param region - region to be pgm header generated for 
++   \param [out] header - header pgm
++ */
 +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
++ */
 +int I_create_cat_rast(struct Cell_head * cat_rast_region,  const char * cat_rast)
 +{
 +    FILE * f_cat_rast;
@@ -3274,7 +4145,6 @@
 +
 +    for(i_row = 0; i_row < cat_rast_region->rows; i_row++) {
 +        fwrite(row_data, sizeof(unsigned char), (cat_rast_region->cols)/sizeof(unsigned char), f_cat_rast);
-+        // TODO when code will be paralelized put it out of the loop
 +        if (ferror(f_cat_rast))
 +        {
 +            fclose(f_cat_rast);
@@ -3289,10 +4159,20 @@
 +
 +static int print_reg(struct Cell_head * intersec, const char * pref)
 +{
-+    G_message("%s:\n n:%f\ns:%f\ne:%f\nw:%f\nns_res:%f\new_res:%f", pref, intersec->north, intersec->south, 
++    G_debug(0, "%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);
 +}
 +
++/*!
++   \brief Find intersection region of two regions.
++
++   \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)
++
++   \return  0 if interection exists
++   \return -1 if regions does not intersect
++ */
 +static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
 +{
 +
@@ -3320,17 +4200,33 @@
 +
 +}
 +
++/*!
++   \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 [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
++
++   \return  0 if interection exists
++   \return -1 if regions do not intersect
++*/
 +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)
 +{
 +    float ns_res, ew_res;
 +
 +    struct Cell_head intersec;
 +
-+    if(A->ns_res != B->ns_res)
++    /* 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;
++    }
 +
-+    if(A->ew_res != B->ew_res)
++    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;
++    }
 +
 +    ns_res = A->ns_res;
 +    ew_res = A->ew_res;
@@ -3353,7 +4249,16 @@
 +    return 0;
 +}
 +
++/*!
++   \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
 +
++   \return  0 on success
++   \return -1 on failure
++*/
 +int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region,  const char * cat_rast)
 +{
 +
@@ -3365,9 +4270,9 @@
 +    int fd_patch_rast, init_shift, step_shift;
 +    unsigned char * patch_data;
 +
-+    char * null_chunk;
++    char * null_chunk_row;
 +
-+    //TODO G_free mapset (aslo in compute  scatts)
++    //TODO G_free mapset (also in compute  scatts)
 +    const char *mapset;
 +
 +    struct Cell_head patch_lines, cat_rast_lines;
@@ -3376,15 +4281,14 @@
 +
 +    f_cat_rast = fopen(cat_rast, "rb+");
 +    if(!f_cat_rast)
-+        return -10;
-+
-+
++        return -1;
++    
 +    /* TODO */
 +    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
 +
 +    if ((mapset = G_find_raster2(patch_rast,"")) == NULL) {
 +        fclose(f_cat_rast);
-+        return -2;
++        return -1;
 +    }
 +
 +    Rast_get_cellhd(patch_rast, mapset, &patch_region);
@@ -3392,10 +4296,10 @@
 +            
 +    if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
 +        fclose(f_cat_rast);
-+        return -3;
++        return -1;
 +    }
 +
-+    null_chunk =  Rast_allocate_null_buf();
++    null_chunk_row =  Rast_allocate_null_buf();
 +
 +    if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
 +
@@ -3408,18 +4312,18 @@
 +
 +    if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
 +        G_message("seek failed");
-+        return -4;
++        return -1;
 +    }
 +
 +    step_shift = cat_rast_region->cols - ncols;
 +    
 +    for(i_row = 0; i_row < nrows; i_row++) {
-+        Rast_get_null_value_row (fd_patch_rast, null_chunk, i_row + patch_bounds.north);
++        Rast_get_null_value_row (fd_patch_rast, null_chunk_row, i_row + patch_bounds.north);
 +
 +        for(i_col = 0; i_col < ncols; i_col++) {
 +            patch_col = patch_bounds.west + i_col;
 +
-+            if(null_chunk[patch_col] != 1) 
++            if(null_chunk_row[patch_col] != 1) 
 +                patch_data[i_col] = 1 & 255;
 +            else {
 +                patch_data[i_col] = 0 & 255;
@@ -3429,29 +4333,38 @@
 +        fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
 +        if (ferror(f_cat_rast))
 +        {
-+            G_free(null_chunk);
++            G_free(null_chunk_row);
 +            fclose(f_cat_rast);
-+            return -5;
++            return -1;
 +        }
 +        if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
 +            G_message("seek failed");
-+            return -6;
++            return -1;
 +        }
 +    }
 +
 +    Rast_close(fd_patch_rast);
-+    G_free(null_chunk);
++    G_free(null_chunk_row);
 +    fclose(f_cat_rast);
 +    return 0;
 +}
 +
-+static inline void update_cat_scatt_plt(CELL ** chunks, char ** null_chunks, int chunk_size, unsigned short * belongs_pix, struct scScatts * scatts)
++/*!
++   \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 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
++*/
++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)
 +{
-+    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunks_pix, max_arr_idx;
++    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunk_rows_pix, max_arr_idx;
 +
-+    CELL * b_1_chunks;
-+    CELL * b_2_chunks;
-+    char * band_1_null_chunks,* band_2_null_chunks;
++    CELL * b_1_chunk_rows;
++    CELL * b_2_chunk_rows;
++    char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
 +
 +    struct Range b_1_range, b_2_range;
 +    int b_1_range_size;
@@ -3460,11 +4373,11 @@
 +
 +    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
 +    {   
-+        b_1_chunks = chunks[scatts_bands[i_scatt * 2]];
-+        b_2_chunks = chunks[scatts_bands[i_scatt * 2 + 1]];
++        b_1_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2]];
++        b_2_chunk_rows = chunk_rows[scatts_bands[i_scatt * 2 + 1]];
 +
-+        band_1_null_chunks =  null_chunks[scatts_bands[i_scatt * 2]];
-+        band_2_null_chunks =  null_chunks[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_range = scatts->scatts_arr[i_scatt]->band_1_range;
 +        b_2_range = scatts->scatts_arr[i_scatt]->band_2_range;
@@ -3472,14 +4385,14 @@
 +        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_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++        for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
 +        {
-+            if(!belongs_pix[i_chunks_pix] || 
-+                band_1_null_chunks[i_chunks_pix] == 1 || 
-+                band_2_null_chunks[i_chunks_pix] == 1)                
++            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)                
 +                continue;
 +
-+            array_idx = b_1_chunks[i_chunks_pix] - b_1_range.min + (b_2_chunks[i_chunks_pix] - b_2_range.min) * b_1_range_size;
++            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;
 +
 +            if(array_idx < 0 || array_idx >= max_arr_idx) {
 +                G_warning ("pixel out of range");
@@ -3490,15 +4403,32 @@
 +    }
 +}
 +
-+static inline int compute_scatts_from_chunk(struct scCats * scatt_plts, struct scCats * scatt_conds, 
-+                                            CELL ** chunks, char ** null_chunks, int chunk_size, FILE ** f_cats_rasts_in,
-+                                            FILE ** f_cats_rasts_out, struct Cell_head *region, int i_chunk)
++/*!
++   \brief Computes scatter plots data from chunk_rows.
++
++   \param scatts pointer to scScatts struct of type SC_SCATT_DATA, where are computed scatter plots stored
++   \param scatt_conds pointer to scScatts struct of type SC_SCATT_CONDITIONS, where are selected areas (condtitions)stored
++
++   \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 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)
 +{
 +
-+    int i_chunks_pix, i_cat, i_scatt, n_a_scatts, i_cond;
++    int i_chunk_rows_pix, i_cat, i_scatt, n_a_scatts, i_cond;
 +    int cat_id, scatt_plts_cat_idx, array_idx, max_arr_idx;
-+    char * band_1_null_chunks,* band_2_null_chunks;
-+    
++    char * band_1_null_chunk_rows,* band_2_null_chunk_rows;
++    CELL * cat_rast_row;
++
 +    struct scScatts * scatts_conds;
 +    struct scScatts * scatt_plts_scatts;
 +    struct scdScattData * conds;
@@ -3509,12 +4439,13 @@
 +    int * scatts_bands;
 +    struct scdScattData ** scatts_arr;
 +
-+    CELL * b_1_chunks;
-+    CELL * b_2_chunks;
++    CELL * b_1_chunk_rows;
++    CELL * b_2_chunk_rows;
 +    unsigned char * i_scatt_conds;
 +
-+    unsigned short * belongs_pix = (unsigned short *) G_malloc(chunk_size * sizeof(unsigned short)); 
-+    unsigned char * rast_pixs = (unsigned char *) G_malloc(chunk_size * sizeof(unsigned char));
++    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));
++    cat_rast_row =  Rast_allocate_c_buf();
 +
 +    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
 +    {
@@ -3522,49 +4453,49 @@
 +
 +        cat_id = scatt_conds->cats_ids[i_cat];
 +
-+        scatt_plts_cat_idx = scatt_plts->cats_idxs[cat_id];
++        scatt_plts_cat_idx = scatts->cats_idxs[cat_id];
 +        if(scatt_plts_cat_idx < 0)
 +            continue;
 +
-+        scatt_plts_scatts = scatt_plts->cats_arr[scatt_plts_cat_idx];
++        scatt_plts_scatts = scatts->cats_arr[scatt_plts_cat_idx];
 +
-+        G_zero(belongs_pix, chunk_size * sizeof(unsigned short));
++        G_zero(belongs_pix, chunk_row_size * sizeof(unsigned short));
 +
-+        if(!scatts_conds->n_a_scatts && !f_cats_rasts_in[i_cat]) {
++        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_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)                
-+                    belongs_pix[i_chunks_pix] = 1;
++                for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)                
++                    belongs_pix[i_chunk_rows_pix] = 1;
 +            }
 +        }
 +        else
 +        {
 +            scatts_bands = scatts_conds->scatts_bands;
 +
-+            if(f_cats_rasts_in[i_cat])
++            if(f_cats_rasts_conds[i_cat])
 +         
-+                fread(rast_pixs, sizeof(unsigned char), (chunk_size)/sizeof(unsigned char), f_cats_rasts_in[i_cat]);
-+                if (ferror(f_cats_rasts_in[i_cat]))
++                fread(rast_pixs, sizeof(unsigned char), (chunk_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.");
 +                    return -1;
 +                }
-+                for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++                for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
 +                {
-+                    if(rast_pixs[i_chunks_pix] != 0 & 255)
-+                        belongs_pix[i_chunks_pix] = 1;
++                    if(rast_pixs[i_chunk_rows_pix] != 0 & 255)
++                        belongs_pix[i_chunk_rows_pix] = 1;
 +                }
 +
 +            // test every defined conditions in scatter plots
 +            for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
 +            {   
-+                b_1_chunks =  chunks[scatts_bands[i_scatt * 2]];
-+                b_2_chunks =  chunks[scatts_bands[i_scatt * 2 + 1]];
++                b_1_chunk_rows =  chunk_rows[scatts_bands[i_scatt * 2]];
++                b_2_chunk_rows =  chunk_rows[scatts_bands[i_scatt * 2 + 1]];
 +
-+                band_1_null_chunks =  null_chunks[scatts_bands[i_scatt * 2]];
-+                band_2_null_chunks =  null_chunks[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]];
 +
 +                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
 +
@@ -3576,49 +4507,48 @@
 +                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_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++                for(i_chunk_rows_pix = 0; i_chunk_rows_pix < chunk_row_size; i_chunk_rows_pix++)
 +                {
-+                    if(belongs_pix[i_chunks_pix] || 
-+                       band_1_null_chunks[i_chunks_pix] == 1 || 
-+                       band_2_null_chunks[i_chunks_pix] == 1)
++                    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)
 +                        continue;
 +
-+                    array_idx = b_1_chunks[i_chunks_pix] - b_1_range.min + (b_2_chunks[i_chunks_pix] - b_2_range.min) * b_1_range_size;
++                    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 */
 +                    if(array_idx < 0 || array_idx >= max_arr_idx) {
 +                        G_warning ("pixel out of range");
 +                        continue;
 +                    }
 +                    if(i_scatt_conds[array_idx])
-+                        belongs_pix[i_chunks_pix] = 1;
++                        belongs_pix[i_chunk_rows_pix] = 1;
 +                }                
 +            }
 +        }
 +
-+        if(f_cats_rasts_out[i_cat]) {
-+            for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+                rast_pixs[i_chunks_pix] = belongs_pix[i_chunks_pix]  & 255;
++        if(fd_cats_rasts[i_cat] >= 0) {
++            Rast_set_null_value(cat_rast_row, Rast_window_cols(), CELL_TYPE); 
 +
-+            fwrite(rast_pixs, sizeof(unsigned char), (chunk_size)/sizeof(unsigned char), f_cats_rasts_out[i_cat]);
-+            // TODO when code will be paralelized put it out of the loop
-+            if (ferror(f_cats_rasts_out[i_cat]))
-+            {
-+                G_free(rast_pixs);
-+                G_free(belongs_pix);
-+                G_debug(3, "Unable to write into file.");
-+                return -1;
-+            }
++            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];
++
++            Rast_put_c_row (fd_cats_rasts[i_cat], cat_rast_row); 
 +        }
 +
-+        update_cat_scatt_plt(chunks, null_chunks, chunk_size, belongs_pix, scatt_plts_scatts);
++        update_cat_scatt_plts(chunk_rows, null_chunk_rows, chunk_row_size, belongs_pix, scatt_plts_scatts);
 +    }
 +
++    G_free(cat_rast_row);
 +    G_free(rast_pixs);
 +    G_free(belongs_pix);
 +
 +    return 0;
 +}
 +
++/*!
++   \brief Get list if bands needed to be opened for analysis from scCats struct.
++*/
 +static void get_needed_bands(struct scCats * cats, int * b_needed_bands)
 +{
 +    // results in b_needed_bands - array of bools - if item has value 1, band (defined by item index) is needed to be opened
@@ -3637,8 +4567,11 @@
 +    return;
 +}
 +
-+static void free_compute_scatts_data(int * fd_bands, CELL ** chunks, char ** null_chunks, int * n_a_bands, int * bands_ids, 
-+                                     FILE ** f_cats_rasts_in, FILE ** f_cats_rasts_out, int n_a_cats)
++/*!
++   \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, 
++                                     int * fd_cats_rasts, FILE ** f_cats_rasts_conds, int n_a_cats)
 +{
 +    int i, band_id;
 +
@@ -3647,25 +4580,27 @@
 +        band_id = bands_ids[i];
 +        if(band_id >= 0) {
 +            Rast_close(fd_bands[i]);
-+            G_free(chunks[band_id]);
-+            G_free(null_chunks[band_id]);
++            G_free(chunk_rows[band_id]);
++            G_free(null_chunk_rows[band_id]);
 +        }
 +    }
-+
-+    if(f_cats_rasts_in)
++     
++    if(f_cats_rasts_conds)
 +        for(i = 0; i < n_a_cats; i++)
-+            if(f_cats_rasts_in[i])
-+                fclose(f_cats_rasts_in[i]);
++            if(f_cats_rasts_conds[i])
++                fclose(f_cats_rasts_conds[i]);
 +
-+    if(f_cats_rasts_out)
++    if(fd_cats_rasts)
 +        for(i = 0; i < n_a_cats; i++)
-+            if(f_cats_rasts_out[i])
-+                fclose(f_cats_rasts_out[i]);
++            if(fd_cats_rasts[i] >= 0)
++                Rast_close(fd_cats_rasts[i]);
 +
 +}
 +
-+
-+static int open_cats_rasts_files(const char ** cats_rasts, int n_a_cats, int * cats_ids, const char * mode, FILE ** f_cats_rasts)
++/*!
++   \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;
 +
@@ -3674,17 +4609,20 @@
 +        id_cat = cats_ids[i_cat];
 +
 +        if(cats_rasts[id_cat]) {
-+            f_cats_rasts[i_cat] = fopen(cats_rasts[id_cat], mode);
-+            if(!f_cats_rasts[i_cat]) return -1;
++            fd_cats_rasts[i_cat] = fopen(cats_rasts[id_cat], mode);
++            if(!fd_cats_rasts[i_cat]) return -1;
 +        }
 +        else
-+            f_cats_rasts[i_cat] = NULL;
++            fd_cats_rasts[i_cat] = NULL;
 +    }
 +
 +    return 0;
 +}
 +
-+static int cats_rasts_write_header(int n_a_cats, struct Cell_head * region, FILE ** f_cats_rasts)
++/*!
++   \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 
@@ -3693,37 +4631,49 @@
 +
 +    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
 +    {
-+        if(!f_cats_rasts[i_cat])
++        if(!fd_cats_rasts[i_cat])
 +            continue;
 +
-+        fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cats_rasts[i_cat]);
-+        if (ferror(f_cats_rasts[i_cat])) return -1;
++        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;
 +
 +}
 +
-+//TODO change name: I_UpdateScattData???
++/*!
++   \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 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
++*/
 +int I_compute_scatts(struct Cell_head *region, struct scCats * scatt_conds, const char ** bands, 
-+                    int n_bands, struct scCats * scatt_plts, const char ** cats_rasts_in, const char ** cats_rasts_out) 
-+{/*scatt_plts must be zeros! */
-+    if (n_bands != scatt_plts->n_bands ||
++                    int n_bands, const char ** cats_rasts_conds,  struct scCats * scatts, const char ** cats_rasts) 
++{
++    if (n_bands != scatts->n_bands ||
 +        n_bands != scatt_conds->n_bands)
-+        return -1;
++        return -4;
 +
 +    const char *mapset;
++    char header[1024];
 +
-+    FILE * f_cats_rasts_out[scatt_conds->n_a_cats];
-+    FILE * f_cats_rasts_in[scatt_conds->n_a_cats];
++    int fd_cats_rasts[scatt_conds->n_a_cats];
++    FILE * f_cats_rasts_conds[scatt_conds->n_a_cats];
 +
-+    CELL * chunks[n_bands];
-+    char * null_chunks[n_bands];
++    CELL * chunk_rows[n_bands];
++    char * null_chunk_rows[n_bands];
 +
 +    RASTER_MAP_TYPE data_type;
 +
 +    int nrows, i_band, id_band, n_a_bands, band_id, 
-+        chunk_size, i, i_chunk, i_row, head_nchars, i_cat;
++        chunk_row_size, i, i_row, head_nchars, i_cat, id_cat;
 +    int fd_bands[n_bands];
 +    for(i_band = 0; i_band < n_bands; i_band++)
 +        fd_bands[i_band] = -1;
@@ -3736,7 +4686,7 @@
 +    memset(b_needed_bands, 0, (size_t)n_bands * sizeof(int));
 +
 +    get_needed_bands(scatt_conds, &b_needed_bands[0]);
-+    get_needed_bands(scatt_plts, &b_needed_bands[0]);
++    get_needed_bands(scatts, &b_needed_bands[0]);
 +
 +    Rast_set_window(region);
 +
@@ -3749,15 +4699,15 @@
 +
 +            /* TODO solve  returns*/
 +            if ((mapset = G_find_raster2(bands[id_band],"")) == NULL) {
-+                free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
++                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 -1;
++                return -4;
 +            }
 +            
 +            if ((fd_bands[n_a_bands] = Rast_open_old(bands[id_band], mapset)) < 0) {
-+                free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
++                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 -1;
++                return -5;
 +            }
 +
 +            //TODO check data type, minimum and maximum value
@@ -3766,8 +4716,8 @@
 +            //    return -1;
 +
 +            //What happens if it is not CELL tyoe
-+            chunks[id_band] =  Rast_allocate_c_buf();
-+            null_chunks[id_band] =  Rast_allocate_null_buf();
++            chunk_rows[id_band] =  Rast_allocate_c_buf();
++            null_chunk_rows[id_band] =  Rast_allocate_null_buf();
 +
 +            bands_ids[n_a_bands] = id_band;
 +
@@ -3775,33 +4725,30 @@
 +        }
 +    }
 +
-+    if (open_cats_rasts_files(cats_rasts_out, scatt_conds->n_a_cats, scatt_conds->cats_ids, "wb", f_cats_rasts_out) != 0) {
-+        free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
-+                                 &bands_ids[0], &f_cats_rasts_out[0], NULL, scatt_conds->n_a_cats);
-+        return -1;
++    for(i_cat = 0; i_cat < scatts->n_a_cats; i_cat++)
++    {
++        id_cat = scatts->cats_ids[i_cat];
++        if(cats_rasts[id_cat]) {
++            fd_cats_rasts[i_cat] = Rast_open_new(cats_rasts[id_cat], CELL_TYPE);   
++        }
++        else
++            fd_cats_rasts[i_cat] = -1;
 +    }
 +
-+    head_nchars = cats_rasts_write_header(scatt_conds->n_a_cats, region, f_cats_rasts_out);
-+    if (head_nchars < 0) {
-+        free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
-+                                 &bands_ids[0], &f_cats_rasts_out[0], NULL, scatt_conds->n_a_cats);
-+        return -1;
-+    }
++    head_nchars =  get_cat_rast_header(region, header);
 +
-+    if (open_cats_rasts_files(cats_rasts_in, scatt_conds->n_a_cats, scatt_conds->cats_ids, "rb", f_cats_rasts_in) != 0) {
-+        free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
-+                                 &bands_ids[0], &f_cats_rasts_out[0], &f_cats_rasts_in[0], scatt_conds->n_a_cats);
-+        return -1;
++    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;
 +    }
 +
 +    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
-+        if(f_cats_rasts_in[i_cat])
-+            fseek(f_cats_rasts_in[i_cat] , head_nchars, SEEK_SET);
++        if(f_cats_rasts_conds[i_cat])
++            fseek(f_cats_rasts_conds[i_cat] , head_nchars, SEEK_SET);
 +
-+    i_chunk = 0;
-+
 +    nrows = Rast_window_rows();
-+    chunk_size = Rast_window_cols();
++    chunk_row_size = Rast_window_cols();
 +
 +    for (i_row = 0; i_row < nrows; i_row++)
 +    {
@@ -3809,538 +4756,19 @@
 +        {   
 +            band_id = bands_ids[i_band];
 +            G_debug(3, "Reading data for band %d", band_id);
-+            Rast_get_c_row(fd_bands[i_band], chunks[band_id], i_row);
-+            Rast_get_null_value_row (fd_bands[i_band], null_chunks[band_id], i_row);
++            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);
 +        }
-+        if(compute_scatts_from_chunk(scatt_plts, scatt_conds, chunks, null_chunks, chunk_size,  &f_cats_rasts_in[0], &f_cats_rasts_out[0], region, i_chunk) == -1) 
++        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) 
 +        {
-+            free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
-+                               &bands_ids[0], &f_cats_rasts_out[0], &f_cats_rasts_in[0], 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);
++            return -3;
 +        }
 + 
 +    }
-+    free_compute_scatts_data(&fd_bands[0], &chunks[0], &null_chunks[0], &n_a_bands, 
-+                             &bands_ids[0], &f_cats_rasts_out[0], &f_cats_rasts_in[0], scatt_conds->n_a_cats); 
++    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 0;    
 +}
 \ No newline at end of file
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c	(revision 0)
-+++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,342 @@
-+/*!
-+   \file lib/imagery/scatt_cat_rast.c
-+
-+   \brief Imagery library - functions for wx Scatter Plot Tool.
-+
-+   Low level functions used by wx Scatter Plot Tool.
-+
-+   Copyright (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.
-+
-+   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
-+ */
-+
-+#include <grass/raster.h>
-+#include <grass/imagery.h>
-+#include <grass/gis.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+//TODO split formulas to be more understandable
-+static void id_scatt_to_bands(const int scatt_id, const int n_bands, int * band_1, int * band_2)
-+{   
-+    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);
-+
-+    * band_2 = scatt_id - ((* band_1) * (2 * n_b1 + 1) - (* band_1) * (* band_1)) / 2 + (* band_1) + 1;
-+
-+    return;
-+}
-+
-+static void bands_to_id_scatt(const int band_1, const int band_2, 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;
-+
-+    return;
-+}
-+
-+void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
-+{
-+    int i_cat;
-+
-+    cats->type = type;
-+
-+    cats->n_cats = 10;
-+    cats->n_a_cats = 0;
-+
-+    cats->n_bands = n_bands;
-+    cats->n_scatts = (n_bands - 1) * n_bands / 2;
-+
-+    cats->cats_arr = (struct scScatts **) malloc(cats->n_cats * sizeof(struct scScatts *));
-+    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
-+
-+    cats->cats_ids = (int *)  malloc(cats->n_cats * sizeof(int));
-+    cats->cats_idxs =(int *)  malloc(cats->n_cats * sizeof(int));
-+
-+    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
-+        cats->cats_idxs[i_cat] = -1;
-+
-+    return;
-+}
-+
-+void I_sc_free_cats(struct scCats * cats)
-+{
-+    int i_cat;
-+
-+    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
-+    {        
-+        if(cats->cats_arr[i_cat])
-+        {   
-+            free(cats->cats_arr[i_cat]->scatt_idxs);
-+            free(cats->cats_arr[i_cat]->scatts_bands);
-+            free(cats->cats_arr[i_cat]->scatts_arr);
-+            free(cats->cats_arr[i_cat]);
-+        }
-+    }
-+
-+    free(cats->cats_ids);
-+    free(cats->cats_idxs);
-+    free(cats->cats_arr);
-+
-+    cats->n_cats = 0;
-+    cats->n_a_cats = 0;
-+    cats->n_bands = 0;
-+    cats->n_scatts = 0;
-+    cats->type = -1;
-+
-+    return;
-+}
-+
-+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;
-+}
-+
-+int I_sc_add_cat(struct scCats * cats, int cat_id)
-+{
-+    int i_scatt;
-+    int n_a_cats = cats->n_a_cats;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    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;
-+    
-+    cats->cats_arr[n_a_cats] = (struct scScatts *) malloc(sizeof(struct scScatts));
-+
-+    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) malloc(cats->n_scatts * sizeof(struct scdScattData *));
-+    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
-+    
-+    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
-+
-+    cats->cats_arr[n_a_cats]->scatts_bands = (int *) malloc(cats->n_scatts * 2 * sizeof(int));
-+     
-+    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) malloc(cats->n_scatts * sizeof(int));
-+    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
-+        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
-+    
-+    ++cats->n_a_cats;
-+
-+    return 0;
-+}
-+
-+int I_sc_delete_cat(struct scCats * cats, int cat_id)
-+{
-+    int cat_idx, i_cat;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    free(cats->cats_arr[cat_idx]->scatt_idxs);
-+    free(cats->cats_arr[cat_idx]->scatts_bands);
-+    free(cats->cats_arr[cat_idx]->scatts_arr);
-+    free(cats->cats_arr[cat_idx]);
-+
-+    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
-+    {
-+        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
-+        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
-+    }
-+    cats->cats_idxs[cat_id] = -1; 
-+
-+    --cats->n_a_cats;
-+    
-+    return 0;
-+}
-+    
-+
-+int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int band_1, band_2, cat_idx, n_a_scatts;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] >= 0)
-+        return -1;
-+
-+    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
-+        return -1;
-+
-+    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
-+        return -1;
-+
-+    n_a_scatts = scatts->n_a_scatts;
-+
-+    scatts->scatt_idxs[scatt_id] = n_a_scatts;
-+
-+    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;
-+
-+    scatts->scatts_arr[n_a_scatts] = scatt_data;
-+    ++scatts->n_a_scatts;
-+
-+    return 0;
-+}
-+
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 && cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_idx];
-+
-+    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
-+    {
-+        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
-+        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
-+        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
-+    }
-+    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
-+
-+    scatts->scatt_idxs[scatt_id] = -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_id];
-+    scatts->n_a_scatts--;
-+
-+    return 0;
-+}
-+
-+int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
-+{
-+    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
-+    int cat_idx, scatt_idx, ret;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+    
-+    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
-+
-+    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
-+
-+    return 0;
-+}
-+
-+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)
-+{
-+    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)
-+            scatt_data->scatt_vals_arr = (unsigned int *) data;
-+        else {
-+            scatt_data->scatt_vals_arr = (unsigned int *) malloc(n_vals * sizeof(unsigned int));
-+            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
-+        }
-+        scatt_data->b_conds_arr = NULL;
-+    }
-+    else if(type == SC_SCATT_CONDITIONS)
-+    {
-+        if(data)
-+            scatt_data->b_conds_arr = (unsigned char *) data;
-+        else {
-+            scatt_data->b_conds_arr = (unsigned char *) malloc(n_vals * sizeof(unsigned char));
-+            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
-+        }
-+        scatt_data->scatt_vals_arr = NULL;
-+    }
-+
-+    return;
-+}
-+
-+void I_scd_free_scatt_data(struct scdScattData * scatt_data)
-+{
-+
-+    free(scatt_data->b_conds_arr);
-+    free(scatt_data->scatt_vals_arr);
-+
-+    scatt_data = NULL;
-+
-+    return;
-+}
-+
-+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)
-+{
-+
-+    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
-+    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
-+
-+    return;
-+}
-+
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
-+{
-+    if(!scatt_data->b_conds_arr)
-+        return scatt_data->b_conds_arr;
-+    else if(!scatt_data->scatt_vals_arr)
-+        return scatt_data->scatt_vals_arr;
-+
-+    return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
-+{
-+    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
-+        return -1;
-+
-+    if(scatt_data->b_conds_arr)
-+        scatt_data->b_conds_arr[val_idx] = val;
-+    else if(scatt_data->scatt_vals_arr)
-+        scatt_data->scatt_vals_arr[val_idx] = val;
-+    else
-+        return -1;
-+
-+    return 0;
-+}
-Index: lib/vector/vedit/move.c
-===================================================================
---- lib/vector/vedit/move.c	(revision 57336)
-+++ lib/vector/vedit/move.c	(working copy)
-@@ -22,13 +22,16 @@
-   \param List list of primitives to be moved
-   \param move_x,move_y,move_z direction (move_z used only if map is 3D)
-   \param snap enable snapping (see globals.h)
--  
-+  \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+  		 new_id corresponds to same position of id in List
-+  		 null pointer can be passed
-+
-   \return number of modified primitives
-   \return -1 on error
- */
- int Vedit_move_lines(struct Map_info *Map, struct Map_info **BgMap,
- 		     int nbgmaps, struct ilist *List, double move_x,
--		     double move_y, double move_z, int snap, double thresh)
-+		     double move_y, double move_z, int snap, double thresh, struct ilist *new_ids)
- {
-     struct line_pnts *Points;
-     struct line_cats *Cats;
-@@ -84,6 +87,8 @@
- 	if (newline < 0) {
- 	    return -1;
- 	}
-+	if(new_ids)
-+	    Vect_list_append(new_ids, newline);
- 
- 	nlines_moved++;
-     }
-Index: lib/vector/vedit/vertex.c
-===================================================================
---- lib/vector/vedit/vertex.c	(revision 57336)
-+++ lib/vector/vedit/vertex.c	(working copy)
-@@ -26,7 +26,10 @@
-   \param move_x,move_y,move_z direction (move_z is used when map is 3D)
-   \param move_first move only first vertex found in the bounding box
-   \param snap snapping mode (see vedit.h)
--  
-+  \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+  		 new_id corresponds to same position of id in List
-+  		 if feature was not rewritten new id is -1
-+  		 null pointer can be passed
-   \return number of moved verteces
-   \return -1 on error
- */
-@@ -34,11 +37,11 @@
- 		      int nbgmaps, struct ilist *List,
- 		      struct line_pnts *coord, double thresh_coords,
- 		      double thresh_snap, double move_x, double move_y,
--		      double move_z, int move_first, int snap)
-+		      double move_z, int move_first, int snap, struct ilist *new_ids)
- {
-     int nvertices_moved, nlines_modified, nvertices_snapped;
- 
--    int i, j, k;
-+    int i, j, k, newline;
-     int line, type, rewrite;
-     int npoints;
-     double east, north, dist;
-@@ -159,12 +162,17 @@
- 	}			/* for each coord */
- 
- 	if (rewrite) {
--	    if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
-+	    newline = Vect_rewrite_line(Map, line, type, Points, Cats);
-+	    if (newline < 0) {
- 		return -1;
- 	    }
-+	    if(new_ids)
-+		Vect_list_append(new_ids, newline);
- 
- 	    nlines_modified++;
- 	}
-+	else if(new_ids)
-+	    Vect_list_append(new_ids, -1);
-     }				/* for each selected line */
- 
-     /* destroy structures */
-@@ -187,12 +195,15 @@
-   \param List list of lines
-   \param coord points location
-   \param thresh find line in given threshold
--  
-+  \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+  		 new_id corresponds to same position of id in List
-+  		 if feature was not rewritten new id is -1
-+  		 null pointer can be passed
-   \return number of add verteces
-   \return -1 on error
- */
- int Vedit_add_vertex(struct Map_info *Map, struct ilist *List,
--		     struct line_pnts *coord, double thresh)
-+		     struct line_pnts *coord, double thresh, struct ilist *new_ids)
- {
-     int i, j;
-     int type, line, seg;
-@@ -200,6 +211,7 @@
-     double east, north, dist;
-     double *x, *y, *z;
-     double px, py;
-+    int newline;
- 
-     struct line_pnts *Points;
-     struct line_cats *Cats;
-@@ -253,12 +265,17 @@
- 	/* rewrite the line */
- 	if (rewrite) {
- 	    Vect_line_prune(Points);
--	    if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
-+	    newline = Vect_rewrite_line(Map, line, type, Points, Cats);
-+	    if (newline < 0) {
- 		return -1;
- 	    }
-+	    if(new_ids)
-+		Vect_list_append(new_ids, newline);
- 
- 	    nlines_modified++;
- 	}
-+	else if(new_ids)
-+	    Vect_list_append(new_ids, -1);
-     }				/* for each line */
- 
-     /* destroy structures */
-@@ -277,12 +294,15 @@
-   \param List list of selected lines
-   \param coord points location
-   \param thresh threshold value to find a line
--  
-+  \param new_ids list of newly assigned ids for features, which vertexes were moved,
-+  		new_id corresponds to same position of id in List
-+  		if feature was not rewritten new id is -1
-+  		null pointer can be passed
-   \return number of removed vertices
-   \return -1 on error
- */
- int Vedit_remove_vertex(struct Map_info *Map, struct ilist *List,
--			struct line_pnts *coord, double thresh)
-+			struct line_pnts *coord, double thresh, struct ilist *new_ids)
- {
-     int i, j, k;
-     int type, line;
-@@ -290,6 +310,7 @@
-     double east, north;
-     double dist;
-     double *x, *y, *z;
-+    int newline;
- 
-     struct line_pnts *Points;
-     struct line_cats *Cats;
-@@ -336,12 +357,18 @@
- 
- 	if (rewrite) {
- 	    /* rewrite the line */
--	    if (Vect_rewrite_line(Map, line, type, Points, Cats) < 0) {
-+	    newline = Vect_rewrite_line(Map, line, type, Points, Cats); 
-+	    if (newline < 0) {
- 		return -1;
- 	    }
-+	    if(new_ids)
-+		Vect_list_append(new_ids, newline);
- 
- 	    nlines_modified++;
- 	}
-+	else if(new_ids)
-+	    Vect_list_append(new_ids, -1);
-+
-     }				/* for each line */
- 
-     /* destroy structures */



More information about the grass-commit mailing list