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

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Jul 26 18:36:53 PDT 2013


Author: turek
Date: 2013-07-26 18:36:53 -0700 (Fri, 26 Jul 2013)
New Revision: 57287

Added:
   sandbox/turek/scatter_plot/testing_patch.diff
Removed:
   sandbox/turek/scatter_plot/testing_pach.diff
Log:
file name type

Deleted: sandbox/turek/scatter_plot/testing_pach.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_pach.diff	2013-07-27 01:33:01 UTC (rev 57286)
+++ sandbox/turek/scatter_plot/testing_pach.diff	2013-07-27 01:36:53 UTC (rev 57287)
@@ -1,4189 +0,0 @@
-Index: vector/v.edit/main.c
-===================================================================
---- vector/v.edit/main.c	(revision 57285)
-+++ 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 57285)
-+++ include/imagery.h	(working copy)
-@@ -135,6 +135,41 @@
-     
- } IClass_statistics;
- 
-+/* 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;
-+};
-+
-+struct scdScattData
-+{
-+    int n_vals;
-+    //TODO void pointer???
-+    unsigned int  * b_conds_arr;
-+    unsigned int  * scatt_vals_arr;
-+};
-+
- #define SIGNATURE_TYPE_MIXED 1
- 
- #define GROUPFILE "CURGROUP"
-Index: include/defs/vedit.h
-===================================================================
---- include/defs/vedit.h	(revision 57285)
-+++ include/defs/vedit.h	(working copy)
-@@ -34,7 +34,7 @@
- 
- /* 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: include/defs/imagery.h
-===================================================================
---- include/defs/imagery.h	(revision 57285)
-+++ include/defs/imagery.h	(working copy)
-@@ -110,6 +110,29 @@
- 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 I_scd_free_scatt_data(struct scdScattData *);
-+int I_scd_get_data_size(struct scdScattData *);
-+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 I_create_cat_rast(struct Cell_head *, const char *);
-+int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
-+
-+
- /* sig.c */
- int I_init_signatures(struct Signature *, int);
- int I_new_signature(struct Signature *);
-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,631 @@
-+"""!
-+ 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
-+
-+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
-+
-+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):
-+    
-+        self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
-+
-+        scatt_conds = self.scatt_conds_dt.GetData({0 : []})
-+        scatts = self.scatts_dt.GetData({0 : [scatt_id]})
-+
-+        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)
-+        self.scatts_dt.SetData(scatts)
-+
-+    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
-+
-+        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
-+
-+        self.ComputeCatScatts([cat_id])
-+
-+        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)
-+        
-+        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 = None
-+        self.bin_bands_f = []      
-+
-+        self.region = {}
-+
-+    def GetRegion(self):
-+        return self.region
-+
-+    def Create(self, bands):
-+
-+        self.bands = None
-+        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.region = self._parseRegion(region)
-+
-+    def GetBands(self):
-+        return self.bands
-+
-+    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
-+
-+        self.max_n_cats = 10
-+    
-+        self.vals = 256 * 256
-+
-+        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
-+
-+        if self.type == 0:
-+            np_vals = np.zeros(self.vals, dtype = 'uint32')
-+        elif self.type == 1:
-+            #TODO solve proble with short
-+            np_vals = np.zeros(self.vals, dtype = 'uint32')
-+        else:
-+            return -1
-+
-+        np_vals.shape = (256, 256)#TODO hack do it general
-+
-+        self.cats[cat_id][scatt_id] = {
-+                                        'np_vals' : np_vals
-+                                      }
-+
-+        return 1
-+
-+    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']}
-+                        
-+        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)
-+
-+        #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] = self.cats[cat_id][scatt_id]['np_vals']
-+
-+        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 idScattToBands(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 BandsToidScatt(band_1, band_2, n_bands):
-+
-+    if band_2 <  band_1:
-+        tmp = band_1
-+        band_1 = band_2
-+        band_2 = tmp
-+
-+
-+    n_b1 = n_bands - 1
-+
-+    scatt_id = (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_2 - band_1 - 1
-+
-+    return scatt_id
-+
-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 @@
-+"""!
-+ at package scatt_plot.gthreading
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+import os
-+import sys
-+import time
-+import threading
-+import Queue
-+
-+import wx
-+from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
-+
-+class gThread(threading.Thread):
-+    """!Thread for GRASS commands"""
-+    requestId = 0
-+
-+    def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
-+        """!
-+        @param receiver event receiver (used in PostEvent)
-+        """
-+        threading.Thread.__init__(self, **kwds)
-+
-+        if requestQ is None:
-+            self.requestQ = Queue.Queue()
-+        else:
-+            self.requestQ = requestQ
-+
-+        if resultQ is None:
-+            self.resultQ = Queue.Queue()
-+        else:
-+            self.resultQ = resultQ
-+
-+        self.setDaemon(True)
-+
-+        self.receiver = receiver
-+        self._want_abort_all = False
-+
-+        self.start()
-+
-+    def Run(self, *args, **kwds):
-+        """!Run command in queue
-+
-+        @param args unnamed command arguments
-+        @param kwds named command arguments
-+
-+        @return request id in queue
-+        """
-+        gThread.requestId += 1
-+        self.requestQ.put((gThread.requestId, args, kwds))
-+
-+        return gThread.requestId
-+
-+    def GetId(self):
-+         """!Get id for next command"""
-+         return gThread.requestId + 1
-+
-+    def SetId(self, id):
-+        """!Set starting id"""
-+        gThread.requestId = id
-+
-+    def run(self):
-+        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
-+        while True:
-+            requestId, args, kwds = self.requestQ.get()
-+            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
-+                if key in kwds:
-+                    vars()[key] = kwds[key]
-+                    del kwds[key]
-+                else:
-+                    vars()[key] = None
-+
-+            requestTime = time.time()
-+
-+            #if self._want_abort_all and self.requestCmd is not None:
-+            #    self.requestCmd.abort()
-+            #    if self.requestQ.empty():
-+            #        self._want_abort_all = False
-+
-+            # prepare
-+            if self.receiver:
-+                event = wxCmdPrepare(type = 'method',
-+                                     time=requestTime,
-+                                     pid=requestId)
-+
-+                wx.PostEvent(self.receiver, event)
-+
-+                # run command
-+                event = wxCmdRun(type = 'method',
-+                                 pid=requestId)
-+
-+                wx.PostEvent(self.receiver, event)
-+
-+            time.sleep(.1)
-+
-+            ret = None
-+            exception = None
-+            #try:
-+            ret = vars()['callable'](*args, **kwds)
-+            #except Exception as e:
-+            #    exception  = e;
-+
-+            self.resultQ.put((requestId, ret))
-+
-+            time.sleep(.1)
-+
-+          
-+            if self.receiver:
-+                event = wxCmdDone(type = 'cmd',
-+                                  kwds = kwds,
-+                                  args = args, #TODO expand args to kwds
-+                                  ret=ret,
-+                                  exception=exception,
-+                                  pid=requestId)
-+
-+                # send event
-+                wx.PostEvent(self.receiver, event)
-+
-+    def abort(self, abortall=True):
-+        """!Abort command(s)"""
-+        if abortall:
-+            self._want_abort_all = True
-+        if self.requestQ.empty():
-+            self._want_abort_all = False
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/dialogs.py
-===================================================================
---- gui/wxpython/scatt_plot/dialogs.py	(revision 0)
-+++ gui/wxpython/scatt_plot/dialogs.py	(working copy)
-@@ -0,0 +1,612 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+import wx.lib.mixins.listctrl as listmix
-+import wx.lib.flatnotebook  as FN
-+import wx.aui
-+
-+from core          import globalvar
-+from core.gcmd     import GException, GError, RunCommand
-+
-+from gui_core.gselect import Select
-+from 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, BandsToidScatt
-+from scatt_plot.plots       import ScatterPlotWidget
-+
-+
-+class ScattPlotMainDialog(wx.Dialog):
-+    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))
-+
-+        #TODO remove iclass parameter
-+        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)
-+
-+        # Fancy gui
-+        self._mgr = wx.aui.AuiManager(self)
-+        self._addPanes()
-+        self._mgr.Update()
-+
-+        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)
-+
-+        dlgSize = (220, 400)
-+        self.SetMinSize(dlgSize)
-+        self.SetInitialSize(dlgSize)
-+
-+        #fix goutput's pane size (required for Mac OSX)
-+        #if self.gwindow:         
-+        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
-+
-+    def _doLayout(self):
-+
-+        sizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        sizer.Add(item = self.notebook, proportion = 1,
-+                  flag = wx.EXPAND)
-+
-+        self.mainPanel.SetSizer(sizer)
-+
-+        sizer.Fit(self)  
-+        self.Layout()
-+
-+    #TODO split to panel?
-+    def _createCategoryPage(self):
-+        catsPanel = wx.Panel(parent = self)
-+
-+
-+        self.notebook.AddPage(page = catsPanel, 
-+                              text=_('Categories'), 
-+                              name = 'categories')
-+
-+        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)
-+
-+        AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        catsSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        catsSizer.Add(item = self.toolbars['catsList'], proportion = 0)
-+        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND)
-+
-+        catsPanel.SetSizer(catsSizer)
-+
-+    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))
-+
-+        self._mgr.AddPane(self.mainPanel,
-+                              wx.aui.AuiPaneInfo().
-+                              Name("tabs").CaptionVisible(visible = False).
-+                              Center().
-+                              Dockable(False).
-+                              CloseButton(False).Layer(0))
-+
-+    def OnCloseDialog(self, event):
-+        """!Close dialog"""
-+        self.scatt_mgr.CleanUp()
-+        self.Destroy()
-+
-+    def OnSettings(self, event):
-+        pass
-+
-+    def OnSetData(self, event):
-+
-+        dlg = SetDataDialog(parent=self)        
-+
-+        if dlg.ShowModal() == wx.ID_OK:
-+            bands = dlg.GetBands()
-+            self.scatt_mgr.SetData(bands)
-+        
-+        dlg.Destroy()
-+
-+
-+    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()
-+
-+    def OnSettings(self, event):
-+        pass
-+
-+    def OnAddScattPl(self, event):
-+
-+        bands = self.scatt_mgr.GetBands()
-+        if not bands:
-+            GError(_('No data set for scatter plot.'))
-+            return
-+
-+        dlg = AddScattPlotDialog(parent = self, bands = bands)
-+        
-+        if dlg.ShowModal() == wx.ID_OK:
-+            self.scatt_mgr.AddScattPlot(dlg.GetScattId())
-+        
-+        dlg.Destroy()
-+
-+    def EditCatAdd(self):
-+        self._setEditCat(tool_name = 'editCatAdd')
-+
-+    def EditCatRemove(self):
-+        self._setEditCat(tool_name = 'editCatRemove')
-+
-+    def _setEditCat(self, tool_name):
-+        
-+        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.edit_cat_tools[i_tool_name]['toggle'] = False
-+
-+                toolbar = self.toolbars['catsList']
-+                toolbar.ToggleTool(vars(toolbar)[i_tool_name], False)
-+            
-+            self.edit_cat_tools[tool_name]['toggle'] = True
-+            self.scatt_mgr.EditCat(edit_type = self.edit_cat_tools[tool_name]['type'])
-+            return
-+
-+        self.scatt_mgr.EditCat(edit_type = None)
-+        self.edit_cat_tools[tool_name]['toggle'] = False
-+
-+    def GetScattMgr(self):
-+        return  self.scatt_mgr
-+
-+
-+class SetDataDialog(wx.Dialog):
-+
-+    def __init__(self, parent, id  = wx.ID_ANY):
-+        
-+        wx.Dialog.__init__(self, parent, title = ("Select imagery group "), id = id)
-+
-+        self.bands = []
-+
-+
-+        self._createWidgets()
-+        self.group.SetValue("testovaci_1")
-+
-+    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.group = Select(parent = self, type = 'group',
-+                            size = globalvar.DIALOG_GSELECT_SIZE)
-+
-+        # buttons
-+        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+        
-+        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+        self._layout()
-+
-+    def _layout(self):
-+
-+        border = wx.BoxSizer(wx.VERTICAL) 
-+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.group_label, 
-+                                                    sel = self.group))
-+
-+        # buttons
-+        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+        self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+        
-+        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+
-+        dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+                        flag = wx.ALIGN_CENTER)
-+
-+        border.Add(item = dialogSizer, proportion = 0,
-+                   flag = wx.ALL, border = 5)
-+
-+        self.SetSizer(border)
-+        self.Layout()
-+        self.Fit()
-+
-+        # bindings
-+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+    def _addSelectSizer(self, title, sel): 
-+        """!Helper layout function.
-+        """
-+        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+        selTitleSizer.Add(item = title, proportion = 1,
-+                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+        selSizer.Add(item = selTitleSizer, proportion = 0,
-+                     flag = wx.EXPAND)
-+
-+        selSizer.Add(item = sel, proportion = 1,
-+                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+                     border = 5)
-+
-+        return selSizer
-+
-+    def GetBands(self):
-+
-+        return self.bands
-+
-+    def OnClose(self, event):
-+        """!Close dialog
-+        """
-+        if not self.IsModal():
-+            self.Destroy()
-+        event.Skip()
-+
-+    def OnOk(self, event):
-+        """!
-+        """
-+        ret, stdout, err_msg = RunCommand("i.group",
-+                                      getErrorMsg = True,
-+                                      read = True,
-+                                      quiet = True,
-+                                      group = self.group.GetValue().strip(),
-+                                      flags = 'g')
-+
-+        if ret != 0:
-+            GError("%s module failed:\n%s" % ("<i.group>", err_msg))
-+            return
-+
-+        self.bands = stdout.split('\n')
-+
-+        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()
-+
-+class AddScattPlotDialog(wx.Dialog):
-+
-+    def __init__(self, parent, bands, id  = wx.ID_ANY):
-+        
-+        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+        self.bands = bands
-+
-+        self.scatt_id = None
-+
-+        self._createWidgets()
-+
-+    def _createWidgets(self):
-+
-+        self.labels = {}
-+        self.params = {}
-+
-+        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        # buttons
-+        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+        
-+        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+        self._layout()
-+
-+    def _layout(self):
-+
-+        border = wx.BoxSizer(wx.VERTICAL) 
-+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
-+                                                    sel = self.band_1_ch))
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
-+                                                    sel = self.band_2_ch))
-+
-+        # buttons
-+        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+        self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+        
-+        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+
-+        dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+                        flag = wx.ALIGN_CENTER)
-+
-+        border.Add(item = dialogSizer, proportion = 0,
-+                   flag = wx.ALL, border = 5)
-+
-+        self.SetSizer(border)
-+        self.Layout()
-+        self.Fit()
-+
-+        # bindings
-+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+    def _addSelectSizer(self, title, sel): 
-+        """!Helper layout function.
-+        """
-+        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+        selTitleSizer.Add(item = title, proportion = 1,
-+                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+        selSizer.Add(item = selTitleSizer, proportion = 0,
-+                     flag = wx.EXPAND)
-+
-+        selSizer.Add(item = sel, proportion = 1,
-+                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+                     border = 5)
-+
-+        return selSizer
-+
-+    def OnClose(self, event):
-+        """!Close dialog
-+        """
-+        if not self.IsModal():
-+            self.Destroy()
-+        event.Skip()
-+
-+    def OnOk(self, event):
-+        """!
-+        """
-+        band_1 = self.band_1_ch.GetSelection()
-+        band_2 = self.band_2_ch.GetSelection()
-+
-+
-+        if band_1 == band_2:
-+            GError(_("Selected bands must be different."))
-+            return
-+        
-+        #TODO axes selection
-+        if band_1 > band_2:
-+            tmp_band = band_2
-+            band_2 = band_1
-+            band_1 = band_2
-+
-+        self.scatt_id = BandsToidScatt(band_1, band_2, len(self.bands))
-+
-+        event.Skip()
-+
-+    def GetScattId(self):
-+        return self.scatt_id
-+
-+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)
-+
-+    def GetPlot(self):
-+        return self.scatt
-+
-+    def _doLayout(self):
-+        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
-+        self.main_sizer.Add(self.self)
-+
-+        self.panel.SetSizer(self.main_sizer)
-+        self.main_sizer.Fit(self)
-+    
-+    def OnPlotClosed(self, scatt_id):
-+        self.Destroy()
-+
-+class CategoryListCtrl(wx.ListCtrl,
-+                       listmix.ListCtrlAutoWidthMixin,
-+                       listmix.TextEditMixin):
-+
-+    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
-+
-+        wx.ListCtrl.__init__(self, parent, id,
-+                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
-+        self.columns = ((_('Category name'), 'name'),
-+                        (_('Color'), 'color'))
-+        self.Populate(columns = self.columns)
-+        
-+        self.cats_mgr = cats_mgr
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+        self.rightClickedItemIdx = wx.NOT_FOUND
-+        
-+        listmix.ListCtrlAutoWidthMixin.__init__(self)
-+
-+        listmix.TextEditMixin.__init__(self)
-+        
-+        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
-+        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
-+             
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+        self.cats_mgr.deletedCategory.connect(self.Update)
-+        self.cats_mgr.addedCategory.connect(self.Update)
-+
-+    def Update(self, **kwargs):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+    def InitCoreCats(self):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+    def SetVirtualData(self, row, column, text):
-+        attr = self.columns[column][1]
-+        if attr == 'name':
-+            try:
-+                text.encode('ascii')
-+            except UnicodeEncodeError:
-+                GMessage(parent = self, message = _("Please use only ASCII characters."))
-+                return
-+
-+        cat_id = self.cats_mgr.GetCategories()[row]
-+
-+        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
-+        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+        
-+        self.Select(row)
-+        
-+    def Populate(self, columns):
-+        for i, col in enumerate(columns):
-+            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
-+
-+        self.SetColumnWidth(0, 100)
-+        self.SetColumnWidth(1, 100)
-+        
-+    def AddCategory(self):
-+
-+        self.cats_mgr.addedCategory.disconnect(self.Update)
-+        cat_id = self.cats_mgr.AddCategory()
-+        self.cats_mgr.addedCategory.connect(self.Update)
-+
-+        if cat_id < 0:
-+            GError(_("Maximum limit of categories number was reached."))
-+            return
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+                        
-+    def DeleteCategory(self):
-+        indexList = sorted(self.GetSelectedIndices(), reverse = True)
-+        cats = []
-+        for i in indexList:
-+            # remove temporary raster
-+            cat_id = self.cats_mgr.GetCategories()[i]
-+            
-+            cats.append(cat_id)
-+
-+            self.cats_mgr.deletedCategory.disconnect(self.Update)
-+            self.cats_mgr.DeleteCategory(cat_id)
-+            self.cats_mgr.deletedCategory.connect(self.Update)
-+            
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        
-+    def OnSel(self, event): 
-+        self.cats_mgr.SetSelectedCat(event.GetIndex() + 1)
-+
-+        event.Skip()
-+
-+    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-+        indices = []
-+        lastFound = -1
-+        while True:
-+            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
-+            if index == -1:
-+                break
-+            else:
-+                lastFound = index
-+                indices.append(index)
-+        return indices        
-+
-+    def OnEdit(self, event):
-+        currentItem = event.m_itemIndex
-+        currentCol = event.m_col
-+
-+        if currentCol == 1:
-+            dlg = wx.ColourDialog(self)
-+            dlg.GetColourData().SetChooseFull(True)
-+
-+            if dlg.ShowModal() == wx.ID_OK:
-+                color = dlg.GetColourData().GetColour().Get()
-+                color = ':'.join(map(str, color))
-+                self.SetVirtualData(currentItem, currentCol, color)
-+            dlg.Destroy()
-+            wx.CallAfter(self.SetFocus)
-+        
-+        event.Skip()
-+        
-+        
-+    def DeselectAll(self):
-+        """!Deselect all items"""
-+        indexList = self.GetSelectedIndices()
-+        for i in indexList:
-+            self.Select(i, on = 0)
-+         
-+        # no highlight
-+        self.OnCategorySelected(None)
-+        
-+    def OnGetItemText(self, item, col):
-+        attr = self.columns[col][1]
-+        cat_id = self.cats_mgr.GetCategories()[item]
-+
-+        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
-+
-+    def OnGetItemImage(self, item):
-+        return -1
-+
-+    def OnGetItemAttr(self, item):
-+        return None
-Index: gui/wxpython/scatt_plot/toolbars.py
-===================================================================
---- gui/wxpython/scatt_plot/toolbars.py	(revision 0)
-+++ gui/wxpython/scatt_plot/toolbars.py	(working copy)
-@@ -0,0 +1,106 @@
-+"""!
-+ at package scatt_plot.toolbars
-+
-+ at brief Scatter plot - toolbars
-+
-+Classes:
-+ - toolbars::MainToolbar
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+
-+
-+import wx
-+
-+from icons.icon        import MetaIcon
-+from gui_core.toolbars import BaseToolbar, BaseIcons
-+from core.gcmd         import RunCommand
-+
-+class MainToolbar(BaseToolbar):
-+    """!Main toolbar
-+    """
-+    def __init__(self, parent):
-+        BaseToolbar.__init__(self, parent)
-+        
-+        self.InitToolbar(self._toolbarData())
-+        
-+        # realize the toolbar
-+        self.Realize()
-+
-+    def _toolbarData(self):
-+
-+        icons = {
-+                 'set_data'    : MetaIcon(img = 'layer-raster-add',
-+                                         label = _('Set input raster data for plots')),
-+                 'settings'   : BaseIcons['settings'].SetLabel( _('Ssettings')),
-+                 'help'       : MetaIcon(img = 'help',
-+                                         label = _('Show manual')),
-+                 'add_scatt_pl'  : MetaIcon(img = 'layer-raster-analyze',
-+                                            label = _('Add scatter plot'))
-+                }
-+
-+        return self._getToolbarData((
-+                                     ('sat_data', icons["set_data"],
-+                                      self.parent.OnSetData),
-+                                     (None, ),
-+                                     ('add_scatt', icons["add_scatt_pl"],
-+                                      self.parent.OnAddScattPl),
-+                                     #('settings', icons["settings"],
-+                                     # self.parent.OnSettings),  
-+                                     #('help', icons["help"],
-+                                     # self.OnHelp),                    
-+                                     ("quit", BaseIcons['quit'],
-+                                      self.parent.OnCloseDialog)
-+                                    ))
-+
-+    def OnHelp(self, event) :
-+            RunCommand('g.manual',
-+                       entry = 'wxGUI.scatt_plot')
-+
-+class CategoriesToolbar(BaseToolbar):
-+
-+    def __init__(self, parent, cats_list, scatts_dlg):
-+        BaseToolbar.__init__(self, parent)
-+        self.cats_list = cats_list
-+        self.scatts_dlg = scatts_dlg
-+
-+        self.InitToolbar(self._toolbarData())
-+        
-+
-+        # realize the toolbar
-+        self.Realize()
-+
-+
-+    def _toolbarData(self):
-+
-+        icons = {
-+            'editCatAdd'  : MetaIcon(img = 'polygon-create',
-+                                     label = _('Add region to category mode')),
-+            'editCatRemove'  : MetaIcon(img = 'polygon-delete',
-+                                        label = _('Remove region to category mode')),
-+            'addCat'     : MetaIcon(img = 'layer-add',
-+                                    label = _('Add category')),
-+            'deleteCat'  : MetaIcon(img = 'layer-remove',
-+                                    label = _('Delete category'))
-+            }
-+
-+        return  self._getToolbarData((('editCatAdd', icons['editCatAdd'],
-+                                        lambda event: self.scatts_dlg.EditCatAdd(),
-+                                        wx.ITEM_CHECK),
-+                                      ('editCatRemove', icons['editCatRemove'],
-+                                        lambda event: self.scatts_dlg.EditCatRemove(),
-+                                        wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ('addCat', icons["addCat"],
-+                                        lambda event: self.cats_list.AddCategory()),
-+                                     ('deleteCat', icons["deleteCat"],
-+                                        lambda event: self.cats_list.DeleteCategory())))
-+                                    
-+    def GetToolId(self, toolName): #TODO can be useful in base
-+
-+        return vars(self)[toolName]            
-\ No newline at end of file
-Index: gui/wxpython/scatt_plot/core_c.py
-===================================================================
---- gui/wxpython/scatt_plot/core_c.py	(revision 0)
-+++ gui/wxpython/scatt_plot/core_c.py	(working copy)
-@@ -0,0 +1,211 @@
-+"""!
-+ at package scatt_plot.scatt_plot
-+
-+ at brief Functions which work with scatter plot c code.
-+
-+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)
-+"""
-+
-+from multiprocessing import Process, Queue
-+
-+from ctypes import *
-+try:
-+    from grass.lib.imagery import *
-+    from grass.lib.gis import Cell_head, G_get_window
-+
-+except ImportError, e:
-+    sys.stderr.write(_("Loading imagery lib failed"))
-+
-+def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
-+
-+    #return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out)
-+
-+    # Queue object for interprocess communication
-+    q = Queue()
-+
-+    # The separate render process
-+    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
-+                                                    n_bands, scatts, cats_rasts_in, cats_rasts_out, q))
-+    p.start()
-+    ret = q.get()
-+    p.join()
-+
-+    return ret[0], ret[1]
-+
-+def UpdateCatRast(patch_rast, region, cat_rast):
-+
-+    #return ComputeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts)
-+    # Queue object for interprocess communication
-+
-+    #_updateCatRastProcess(patch_rast, region, cat_rast, None)
-+    #return 
-+    q = Queue()
-+    # The separate render process
-+    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
-+    p.start()
-+    #ret = q.get()
-+    p.join()
-+
-+    #return ret[0], ret[1]
-+
-+def CreateCatRast(region, cat_rast):
-+
-+    cell_head = _regionToCellHead(region)
-+    I_create_cat_rast(pointer(cell_head), cat_rast)   
-+
-+def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, output_queue):
-+
-+    #TODO names for types not 0 and 1?
-+    sccats_c, vals_dt = _getComputationStruct(scatts, 0, n_bands)
-+    scatt_conds_c, vals_dt2 = _getComputationStruct(scatt_conds, 1, n_bands)
-+
-+    char_bands = _stringListToCharArr(bands)
-+    char_cats_rasts_out = _stringListToCharArr(cats_rasts_out)
-+    char_cats_rasts_in = _stringListToCharArr(cats_rasts_in)
-+
-+    cell_head = _regionToCellHead(region)
-+
-+    ret = I_compute_scatts(pointer(cell_head),
-+                          pointer(scatt_conds_c),
-+                          pointer(char_bands),
-+                          n_bands,
-+                          pointer(sccats_c),
-+                          pointer(char_cats_rasts_in),
-+                          pointer(char_cats_rasts_out))
-+
-+    I_sc_free_cats(pointer(sccats_c))
-+    I_sc_free_cats(pointer(scatt_conds_c))
-+
-+    output_queue.put((ret, scatts))
-+    #return (ret, scatts)
-+
-+def _regionToCellHead(region):
-+    cell_head = struct_Cell_head()
-+    G_get_window(pointer(cell_head))
-+
-+    convert_dict = {'n' : 'north', 'e' : 'east', 
-+                    'w' : 'west',  's' : 'south', 
-+                    'nsres' : 'ns_res',
-+                    'ewres' : 'ew_res'}
-+
-+    for k, v in region.iteritems():
-+        if k in ["rows", "cols", "cells"]:
-+            v = int(v)
-+        else:
-+            v = float(v)
-+
-+        if convert_dict.has_key(k):
-+            k = convert_dict[k]
-+           
-+        setattr(cell_head, k, v)
-+
-+    return cell_head
-+
-+def _stringListToCharArr(str_list):
-+
-+    arr = c_char_p * len(str_list)
-+    char_arr = arr()
-+    for i, st in enumerate(str_list):
-+        if st:
-+            char_arr[i] = st
-+        else:
-+            char_arr[i] = None
-+
-+    return char_arr
-+
-+def _getComputationStruct(cats, cats_type, n_bands):
-+
-+    sccats = struct_scCats()
-+    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
-+        
-+    #for i in range(sccats.n_a_cats):
-+    #    cat_id = sccats.cats_ids[i]
-+    #    I_sc_delete_cat(pointer(sccats), cat_id)
-+    #    i -= 1
-+
-+    vals_dt = []
-+    for cat_id, scatt_ids in cats.iteritems():
-+        I_sc_add_cat(pointer(sccats), cat_id)
-+
-+        for scatt_id, dt in scatt_ids.iteritems():
-+            # if key is missing condition is always True (full scatter plor is computed)
-+            if cats[cat_id].has_key(scatt_id):
-+
-+                vals = dt["np_vals"]
-+                #TODO hack
-+                vals.shape = (256 * 256)
-+
-+                c_uint_p = ctypes.POINTER(ctypes.c_uint)
-+                scatt_vals = scdScattData()
-+                if cats_type == 0:
-+                    vals[:] = 0
-+                    scatt_vals.scatt_vals_arr = vals.ctypes.data_as(c_uint_p)
-+
-+                else:
-+                    #TODO solve proble with short integer
-+                    scatt_vals.b_conds_arr = vals.ctypes.data_as(c_uint_p)
-+
-+                vals_dt.append(scatt_vals)
-+
-+                #vals_dt.append(data_p)
-+                vals.shape = (256, 256)
-+                I_sc_insert_scatt_data(pointer(sccats),  
-+                                       pointer(scatt_vals),
-+                                       cat_id, scatt_id)
-+
-+    return sccats, vals_dt
-+
-+def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
-+
-+    #TODO names for types not 0 and 1?
-+
-+    cell_head = _regionToCellHead(region)
-+    
-+    
-+    cat_rast
-+    I_insert_patch_to_cat_rast(patch_rast, 
-+                                     pointer(cell_head), 
-+                                     cat_rast)
-+
-+    #print re
-+    #output_queue.put((ret, scatts))
-+    #return (ret, scatts)
-+
-+"""
-+class A:
-+    def __init__(self):        
-+        self.i = 0        
-+
-+    def incr(self):
-+        self.i += 1
-+        return self.i
-+
-+def worker(input, output):
-+    print "ahoj"
-+    for func, args in iter(input.get, 'STOP'):
-+        print "jedu"
-+        result = func.incr
-+        output.put(result)
-+
-+def test():
-+    # Create queues
-+    task_queue = Queue()
-+    done_queue = Queue()
-+
-+    # Start worker processes
-+    a = A()
-+
-+    prc = Process(target=worker, args=(task_queue, done_queue)).start()
-+    task_queue.put((a,1))
-+
-+    data = done_queue.get()
-+    print data
-+    task_queue.put('STOP')
-+"""
-Index: gui/wxpython/scatt_plot/__init__.py
-===================================================================
---- gui/wxpython/scatt_plot/__init__.py	(revision 0)
-+++ gui/wxpython/scatt_plot/__init__.py	(working copy)
-@@ -0,0 +1,8 @@
-+all = [
-+    'dialogs',
-+    'gthreading',
-+    'plots',
-+    'sc_pl_core',
-+    'toolbars',
-+    'core_c',
-+    ]
-Index: gui/wxpython/scatt_plot/plots.py
-===================================================================
---- gui/wxpython/scatt_plot/plots.py	(revision 0)
-+++ gui/wxpython/scatt_plot/plots.py	(working copy)
-@@ -0,0 +1,185 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief Ploting widgets.
-+
-+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 wx
-+import numpy as np
-+import random
-+try:
-+    haveMatPlot = True
-+    import matplotlib
-+    matplotlib.use('WXAgg')
-+    from matplotlib.figure import Figure
-+    from matplotlib.backends.backend_wxagg import \
-+    FigureCanvasWxAgg as FigCanvas, \
-+    NavigationToolbar2WxAgg as NavigationToolbar
-+except ImportError:
-+    haveMatPlot = False
-+
-+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
-+
-+        self._createWidgets()
-+        self._doLayout()
-+        self.scatt_id = scatt_id
-+        self.scatt_mgr = scatt_mgr
-+        self.press_coords = None
-+
-+        self.cidpress = None
-+        self.cidrelease = None
-+
-+    def StartCategoryEdit(self):
-+        'connect to all the events we need'
-+        self.cidpress = self.canvas.mpl_connect(
-+            'button_press_event', self.OnPress)
-+        self.cidrelease = self.canvas.mpl_connect(
-+            'button_release_event', self.OnRelease)
-+        #self.cidmotion = self.canvas.mpl_connect(
-+        #    'motion_notify_event', self.OnRelease)
-+
-+    def OnPress(self, event):
-+        'on button press we will see if the mouse is over us and store some data'
-+
-+        if event.xdata and event.ydata:
-+            self.press_coords = { 'x' : event.xdata, 'y' : event.ydata}
-+        else:
-+            self.press_coords = None
-+
-+    def OnRelease(self, event):
-+        'on release we reset the press data'
-+
-+        if event.xdata and event.ydata and self.press_coords:
-+
-+            bbox = {}
-+            if event.ydata > self.press_coords['y']:
-+                bbox['up_y'] = event.ydata
-+                bbox['btm_y'] = self.press_coords['y']
-+            else:
-+                bbox['up_y'] = self.press_coords['y']
-+                bbox['btm_y'] = event.ydata
-+
-+            if event.xdata > self.press_coords['x']:
-+                bbox['up_x'] = event.xdata
-+                bbox['btm_x'] = self.press_coords['x']
-+            else:
-+                bbox['up_x'] = self.press_coords['x']
-+                bbox['btm_x'] = event.xdata
-+
-+            self.scatt_mgr.SetEditCatData(self.scatt_id, bbox)
-+
-+    def StopCategoryEdit(self):
-+        'disconnect all the stored connection ids'
-+
-+        if self.cidpress:
-+            self.canvas.mpl_disconnect(self.cidpress)
-+        if self.cidrelease:
-+            self.canvas.mpl_disconnect(self.cidrelease)
-+        #self.canvas.mpl_disconnect(self.cidmotion)
-+
-+    def _createWidgets(self):
-+
-+        # Create the mpl Figure and FigCanvas objects. 
-+        # 5x4 inches, 100 dots-per-inch
-+        #
-+        self.dpi = 100
-+        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
-+        self.canvas = FigCanvas(self, -1, self.fig)
-+        
-+        # Since we have only one plot, we can use add_axes 
-+        # instead of add_subplot, but then the subplot
-+        # configuration tool in the navigation toolbar wouldn't
-+        # work.
-+        #
-+        self.axes = self.fig.add_subplot(111)
-+        
-+        # Bind the 'pick' event for clicking on one of the bars
-+        #
-+        self.canvas.mpl_connect('button_press_event', self.on_pick)
-+        
-+
-+        # Create the navigation toolbar, tied to the canvas
-+        #
-+        self.toolbar = NavigationToolbar(self.canvas)
-+        
-+    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.SetSizer(self.main_sizer)
-+        self.main_sizer.Fit(self)
-+    
-+    def Plot(self, scatts, styles):
-+        """ Redraws the figure
-+        """
-+      
-+        self.axes.clear()
-+        for cat_id, cat in scatts.iteritems():
-+            if cat_id == 0:
-+                cmap = matplotlib.cm.jet
-+                cmap.set_bad('w',1.)
-+                cmap._init()
-+                cmap._lut[len(cmap._lut) - 1, -1] = 0
-+            else:
-+                colors = styles[cat_id]['color'].split(":")
-+
-+                cmap = matplotlib.cm.jet
-+                cmap.set_bad('w',1.)
-+                cmap._init()
-+                cmap._lut[len(cmap._lut) - 1, -1] = 0
-+                cmap._lut[:, 0] = int(colors[0])/255.0
-+                cmap._lut[:, 1] = int(colors[1])/255.0
-+                cmap._lut[:, 2] = int(colors[2])/255.0
-+
-+            masked_cat = np.ma.masked_less_equal(cat, 0)
-+
-+            self.axes.imshow(masked_cat, cmap = cmap,  interpolation='nearest')
-+
-+            self.canvas.draw()
-+    
-+    def on_pick(self, event):
-+        pass
-+        # The event received here is of the type
-+        # matplotlib.backend_bases.PickEvent
-+        #
-+        # It carries lots of information, of which we're using
-+        # only a small amount here.
-+        # 
-+        #box_points = event.x
-+        
-+        #msg = "You've clicked on a bar with coords:\n"
-+        
-+        #dlg = wx.MessageDialog(
-+        #    self, 
-+        #    msg, 
-+        #    "Click!",
-+        #    wx.OK | wx.ICON_INFORMATION)
-+
-+        #dlg.ShowModal() 
-+        #dlg.Destroy()        
-+
-+    def on_exit(self, event):
-+            
-+        self.CleanUp()
-+        
-+    def CleanUp(self):
-+        
-+        self.parent.OnPlotClosed(self.scatt_id)
-+        self.Destroy()
-\ No newline at end of file
-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,513 @@
-+"""!
-+ 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, BandsToidScatt
-+
-+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
-+
-+        wx.EvtHandler.__init__(self)
-+        self.giface = giface
-+        self.mapDisp  = giface.GetMapDisplay()
-+        self.mapWin = giface.GetMapWindow()
-+
-+        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)
-+        else:
-+            self.mapWin_conn = None
-+            self.iclass_conn = None
-+
-+        self.tasks_pids = {
-+                            'add_scatt' : -1,
-+                            'set_data' : -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
-+        self.tasks_pids['set_data'] = self.thread.GetId()
-+        self.thread.Run(callable = self.core.SetData, bands = bands)
-+
-+    def SetDataDone(self, event):
-+        self.data_set = True
-+        self.cats_mgr.InitCoreCats()
-+
-+    def OnOutput(self, event):
-+        """!Print thread output according to debug level.
-+        """
-+        print event.text
-+
-+    def GetBands(self):
-+        return self.core.GetBands()
-+
-+    def AddScattPlot(self, scatt_id):
-+
-+        self.tasks_pids['add_scatt'] = 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)
-+
-+        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.ComputeCatScatts, 
-+                                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 self.tasks_pids['add_scatt'] == event.pid:
-+            self.AddScattPlotDone(event)
-+            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 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/vdigit/wxdigit.py
-===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57285)
-+++ gui/wxpython/vdigit/wxdigit.py	(working copy)
-@@ -17,7 +17,7 @@
- (and NumPy would be an excellent candidate for acceleration via
- e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
- 
--(C) 2007-2011 by the GRASS Development Team
-+(C) 2007-2011, 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.
-@@ -27,6 +27,8 @@
- 
- import grass.script.core as grass
- 
-+from grass.pydispatch.signal import Signal
-+
- from core.gcmd        import GError
- from core.debug       import Debug
- from core.settings    import UserSettings
-@@ -176,7 +178,17 @@
-         
-         if self.poMapInfo:
-             self.InitCats()
--        
-+
-+        #TODO signal for errors?
-+        self.featureAdded = Signal('IVDigit.featureAdded')
-+        self.areasDeleted = Signal('IVDigit.areasDeleted')
-+        self.vertexMoved = Signal('IVDigit.vertexMoved')
-+        self.vertexAdded = Signal('IVDigit.vertexAdded')
-+        self.vertexRemoved = Signal('IVDigit.vertexRemoved')
-+        self.featuresDeleted = Signal('IVDigit.featuresDeleted')
-+        self.featuresMoved = Signal('IVDigit.featuresMoved')
-+        self.lineEdited = Signal('IVDigit.lineEdited')
-+
-     def __del__(self):
-         Debug.msg(1, "IVDigit.__del__()")
-         Vect_destroy_line_struct(self.poPoints)
-@@ -394,7 +406,6 @@
-         
-         @return tuple (number of added features, feature ids)
-         """
--        
-         layer = self._getNewFeaturesLayer()
-         cat = self._getNewFeaturesCat()
-         
-@@ -419,10 +430,14 @@
-             return (-1, None)
-         
-         self.toolbar.EnableUndo()
--        
--        return self._addFeature(vtype, points, layer, cat,
--                                self._getSnapMode(), self._display.GetThreshold())
--    
-+
-+        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]})
-+
-+        return ret
-+
-     def DeleteSelectedLines(self):
-         """!Delete selected features
- 
-@@ -434,16 +449,25 @@
-         # colect categories for delete if requested
-         deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
-         catDict = dict()
-+
-+        old_geoms = []
-+        old_areas_cats = []
-         if deleteRec:
-             for i in self._display.selected['ids']:
-+                
-                 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))
-+                
-                 cats = self.poCats.contents
--                for j in range(cats.n_cats):
--                    if cats.field[j] not in catDict.keys():
--                        catDict[cats.field[j]] = list()
--                    catDict[cats.field[j]].append(cats.cat[j])
-+
-+                # catDict was not used -> put into comment
-+                #for j in range(cats.n_cats):
-+                #    if cats.field[j] not in catDict.keys():
-+                #        catDict[cats.field[j]] = list()
-+                #    catDict[cats.field[j]].append(cats.cat[j])
-         
-         poList = self._display.GetSelectedIList()
-         nlines = Vedit_delete_lines(self.poMapInfo, poList)
-@@ -456,7 +480,8 @@
-                 self._deleteRecords(cats)
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+            self.featuresDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
-+
-         return nlines
-             
-     def _deleteRecords(self, cats):
-@@ -512,22 +537,123 @@
- 
-         @return number of deleted 
-         """
-+        if len(self._display.selected['ids']) < 1:
-+            return 0
-+        
-         poList = self._display.GetSelectedIList()
-         cList  = poList.contents
-         
-         nareas = 0
-+        old_geoms = []
-+        old_areas_cats = []
-+
-         for i in range(cList.n_values):
-+
-             if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
-                 continue
--            
-+
-+            area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
-+            if area > 0: 
-+                geoms, cats = self._getaAreaGeomsCats(area)
-+                old_geoms += geoms
-+                old_areas_cats += cats
-+
-             nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
-         
-         if nareas > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
-+            self.areasDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)        
-+
-+        return nareas
-+   
-+
-+    def _getaAreaGeomsCats(self, area):
-+
-+        po_b_list = Vect_new_list()
-+        Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
-+        b_list = po_b_list.contents
-+
-+        geoms = []
-+        areas_cats = []
-+
-+        if b_list.n_values > 0:
-+            for i_line in  range(b_list.n_values):
-+
-+                line = b_list.value[i_line];
-+
-+                geoms.append(self._getGeom(abs(line)))
-+                areas_cats.append(self._getLineAreasCategories(abs(line)))
-         
--        return nareas
-+        Vect_destroy_list(po_b_list);
-+
-+        return geoms, areas_cats
-+
-+    def _getLineAreasCategories(self, ln_id):
-+
-+        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
-+        if ltype != GV_BOUNDARY:
-+            return []
-+
-+        cats = [None, None]
-+
-+        left = c_int()
-+        right = c_int()
-+
-+        if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
-+            areas = [left.value, right.value]
-+
-+            for i, a in enumerate(areas):
-+                if a > 0: 
-+                    centroid = Vect_get_area_centroid(self.poMapInfo, a)
-+                    if centroid <= 0:
-+                        continue
-+                    c = self._getCategories(centroid)
-+                    if c:
-+                        cats[i] = c
-+
-+        return cats
-+
-+    def _getCategories(self, ln_id):
-+        
-+        poCats = Vect_new_cats_struct()
-+        if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
-+            Vect_destroy_cats_struct(poCats)
-+            return None
-+
-+        cCats = poCats.contents
-+
-+        cats = {}
-+        for j in range(cCats.n_cats):
-+            if cats.has_key(cCats.field[j]):
-+                cats[cCats.field[j]].append(cCats.cat[j])
-+            else:
-+                cats[cCats.field[j]] = [cCats.cat[j]]
-     
-+        Vect_destroy_cats_struct(poCats)
-+        return cats
-+
-+    def _getGeom(self, ln_id):
-+
-+        poPoints = Vect_new_line_struct()
-+        if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
-+            Vect_destroy_line_struct(poPoints)
-+            return None
-+
-+        geom = self._convertGeom(poPoints)
-+        Vect_destroy_line_struct(poPoints)
-+        return geom
-+
-+    def _convertGeom(self, poPoints):
-+
-+        Points = poPoints.contents
-+
-+        pts_geom = []
-+        for j in range(Points.n_points):
-+            pts_geom.append((Points.x[j], Points.y[j]))
-+
-+        return pts_geom
-+
-     def MoveSelectedLines(self, move):
-         """!Move selected features
- 
-@@ -536,16 +662,39 @@
-         if not self._checkMap():
-             return -1
-         
-+        nsel = len(self._display.selected['ids'])
-+        if nsel < 1:
-+            return -1   
-+        
-         thresh = self._display.GetThreshold()
-         snap   = self._getSnapMode()
-         
-         poList = self._display.GetSelectedIList()
-+
-+        old_geoms = []
-+        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()
-         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)
-+
-         Vect_destroy_list(poList)
-         
-+        cList = poNewIds.contents
-+
-+        if nlines > 0:
-+            new_areas_cats = []
-+            for i in range(cList.n_values):
-+                new_id = cList.value[i]
-+                new_areas_cats.append(self._getLineAreasCategories(new_id))
-+
-+        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 @@
-         if nlines > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+ 
-+            self.featuresMoved.emit(move = move, 
-+                                    old_geoms = old_geoms, 
-+                                    old_areas_cats = old_areas_cats, 
-+                                    new_areas_cats = new_areas_cats)
-         return nlines
- 
-     def MoveSelectedVertex(self, point, move):
-@@ -571,20 +724,33 @@
-         
-         if len(self._display.selected['ids']) != 1:
-             return -1
--        
-+
-+        # move only first found vertex in bbox 
-+        poList = self._display.GetSelectedIList()
-+
-+        cList = poList.contents
-+        old_geom = self._getGeom(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)
--        
--        # move only first found vertex in bbox 
--        poList = self._display.GetSelectedIList()
-+
-+        poNewIds = Vect_new_list()
-         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(),
-                                   move[0], move[1], 0.0,
--                                  1, self._getSnapMode())
-+                                  1, self._getSnapMode(), poNewIds)
-         Vect_destroy_list(poList)
--        
-+
-+        new_id = poNewIds.contents.value[0]
-+        Vect_destroy_list(poNewIds)
-+
-+        if new_id > -1:
-+            new_geom = self._getGeom(new_id)
-+            new_areas_cats = self._getLineAreasCategories(new_id)
-+
-         if moved > 0 and self._settings['breakLines']:
-             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
-                                           None)
-@@ -592,7 +758,13 @@
-         if moved > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+
-+        if new_id > -1:
-+            self.vertexMoved.emit(new_geom = new_geom,  
-+                                  new_areas_cats = new_areas_cats, 
-+                                  old_areas_cats = old_areas_cats, 
-+                                  old_geom = old_geom)
-+
-         return moved
- 
-     def AddVertex(self, coords):
-@@ -681,6 +853,9 @@
-             self._error.ReadLine(line)
-             return -1
-         
-+        old_geom = self._getGeom(line)
-+        old_areas_cats = self._getLineAreasCategories(line)
-+
-         # build feature geometry
-         Vect_reset_line(self.poPoints)
-         for p in coords:
-@@ -703,7 +878,15 @@
-         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, 
-+                                 old_areas_cats = old_areas_cats, 
-+                                 new_geom = new_geom, 
-+                                 new_areas_cats = new_areas_cats)
-+
-         return newline
- 
-     def FlipLine(self):
-@@ -1510,26 +1693,49 @@
-             return 0
-         
-         poList  = self._display.GetSelectedIList()
-+        cList = poList.contents
-+        
-+        old_geom = self._getGeom(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()
-+
-         if add:
-             ret = Vedit_add_vertex(self.poMapInfo, poList,
--                                   self.poPoints, thresh)
-+                                   self.poPoints, thresh, poNewIds)
-         else:
-             ret = Vedit_remove_vertex(self.poMapInfo, poList,
--                                      self.poPoints, thresh)
-+                                      self.poPoints, thresh, poNewIds)
-+
-+        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 not add and ret > 0 and self._settings['breakLines']:
-             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
-                                           None)
--        
-+
-         if ret > 0:
-             self._addChangeset()
--                
-+
-+        if new_id > -1:
-+            if add:
-+                self.vertexAdded.emit(old_geom = old_geom, new_geom = new_geom)
-+            else:
-+                self.vertexRemoved.emit(old_geom = old_geom, 
-+                                        new_geom = new_geom,
-+                                        old_areas_cats = old_areas_cats,
-+                                        new_areas_cats = new_areas_cats)
-+
-         return 1
-     
-     def GetLineCats(self, line):
-Index: gui/wxpython/vdigit/toolbars.py
-===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57285)
-+++ 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)
-@@ -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
-===================================================================
---- gui/wxpython/Makefile	(revision 57285)
-+++ 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)
- 
-Index: gui/wxpython/mapdisp/toolbars.py
-===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57285)
-+++ 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 57285)
-+++ 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
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
-+
-+        from scatt_plot.dialogs import ScattPlotMainDialog
-+        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
-+        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
-+
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
-Index: lib/vector/vedit/move.c
-===================================================================
---- lib/vector/vedit/move.c	(revision 57285)
-+++ 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 57285)
-+++ 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 */
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c	(revision 0)
-+++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,321 @@
-+/*!
-+   \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_vals, 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_vals->b_conds_arr && cats->type == 1)
-+        return -1;
-+
-+    if(!scatt_vals->scatt_vals_arr && cats->type == 0)
-+        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_vals;
-+    ++scatts->n_a_scatts;
-+
-+    return 0;
-+}
-+
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_vals, 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_vals = 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_vals = 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_vals, int n_vals, int type)
-+{
-+    scatt_vals->n_vals = n_vals;
-+
-+    if(type == 0)
-+    {   
-+        scatt_vals->scatt_vals_arr = (unsigned int *) malloc(n_vals * sizeof(unsigned int));
-+        memset(scatt_vals->scatt_vals_arr, 0, n_vals * sizeof(unsigned int));
-+        scatt_vals->b_conds_arr = NULL;
-+    }
-+    else if(type == 1)
-+    {   
-+        scatt_vals->b_conds_arr = (unsigned short *) malloc(n_vals * sizeof(unsigned short));
-+        memset(scatt_vals->b_conds_arr, 0, n_vals * sizeof(unsigned short));
-+        scatt_vals->scatt_vals_arr = NULL;
-+    }
-+
-+    return;
-+}
-+
-+void I_scd_free_scatt_data(struct scdScattData * scatt_vals)
-+{
-+
-+    free(scatt_vals->b_conds_arr);
-+    free(scatt_vals->scatt_vals_arr);
-+
-+    scatt_vals = NULL;
-+
-+    return;
-+}
-+
-+int I_scd_get_data_size(struct scdScattData * scatt_vals)
-+{
-+    return scatt_vals->n_vals;
-+}
-+
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_vals)
-+{
-+    if(!scatt_vals->b_conds_arr)
-+        return scatt_vals->b_conds_arr;
-+    else if(!scatt_vals->scatt_vals_arr)
-+        return scatt_vals->scatt_vals_arr;
-+
-+    return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_vals, unsigned int val_idx, unsigned int val)
-+{
-+    if(val_idx < 0 && val_idx >  scatt_vals->n_vals)
-+        return -1;
-+
-+    if(scatt_vals->b_conds_arr)
-+        scatt_vals->b_conds_arr[val_idx] = val;
-+    else if(scatt_vals->scatt_vals_arr)
-+        scatt_vals->scatt_vals_arr[val_idx] = val;
-+    else
-+        return -1;
-+
-+    return 0;
-+}
-Index: lib/imagery/scatt.c
-===================================================================
---- lib/imagery/scatt.c	(revision 0)
-+++ lib/imagery/scatt.c	(working copy)
-@@ -0,0 +1,582 @@
-+/*!
-+   \file lib/imagery/scatt.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>
-+
-+
-+static const int CAT_RAST_SCATT_SEL = 2;
-+static const int CAT_RAST_RAST_SEL = 1;
-+static const int  CAT_RAST_NULL = 0;
-+
-+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);
-+}
-+
-+int I_create_cat_rast(struct Cell_head * cat_rast_region,  const char * cat_rast)
-+{
-+    FILE * f_cat_rast;
-+    char cat_rast_header[1024];//TODO magic number 
-+    int i_row, i_col;
-+    int head_nchars;
-+
-+    unsigned char * row_data;
-+
-+    f_cat_rast = fopen(cat_rast, "wb");
-+    if(!f_cat_rast)
-+        return -1;
-+
-+    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
-+
-+    fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
-+    if (ferror(f_cat_rast)){
-+        fclose(f_cat_rast);
-+        return -1;
-+    }
-+
-+    row_data = (unsigned char *) G_malloc(cat_rast_region->cols * sizeof(unsigned char));
-+    for(i_col = 0; i_col < cat_rast_region->cols; i_col++)
-+        row_data[i_col] = 0 & 255;
-+
-+    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);
-+            G_debug(3, "Unable to write into file.");
-+            return -1;
-+        }
-+    }
-+
-+    fclose(f_cat_rast);
-+    return 0;
-+}
-+
-+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, 
-+               intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
-+}
-+
-+static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
-+{
-+
-+    if(B->north < A->south) return -1;
-+    else if(B->north > A->north) intersec->north = A->north;
-+    else intersec->north = B->north;
-+
-+    if(B->south > A->north) return -1;
-+    else if(B->south < A->south) intersec->south = A->south;
-+    else intersec->south = B->south;
-+
-+    if(B->east < A->west) return -1;
-+    else if(B->east > A->east) intersec->east = A->east;
-+    else intersec->east = B->east;
-+
-+    if(B->west > A->east) return -1;
-+    else if(B->west < A->west) intersec->west = A->west;
-+    else intersec->west = B->west;
-+
-+    if(intersec->north == intersec->south) return -1;
-+
-+    if(intersec->east == intersec->west) return -1;
-+
-+    return 0;
-+
-+}
-+
-+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)
-+        return -1;
-+
-+    if(A->ew_res != B->ew_res)
-+        return -1;
-+
-+    ns_res = A->ns_res;
-+    ew_res = A->ew_res;
-+
-+    if(regions_intersecion(A, B, &intersec) == -1)
-+        return -1;
-+
-+    A_bounds->north = ceil((A->north - intersec.north - ns_res * 0.5) / ns_res);
-+    A_bounds->south = ceil((A->north - intersec.south - ns_res * 0.5) / ns_res);
-+
-+    A_bounds->east = ceil((intersec.east - A->west - ew_res * 0.5) / ew_res);
-+    A_bounds->west = ceil((intersec.west - A->west - ew_res * 0.5) / ew_res);
-+
-+    B_bounds->north = ceil((B->north - intersec.north - ns_res * 0.5) / ns_res);
-+    B_bounds->south = ceil((B->north - intersec.south - ns_res * 0.5) / ns_res);
-+
-+    B_bounds->east = ceil((intersec.east - B->west - ew_res * 0.5) / ew_res);
-+    B_bounds->west = ceil((intersec.west - B->west - ew_res * 0.5) / ew_res);
-+
-+    return 0;
-+}
-+
-+
-+int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region,  const char * cat_rast)
-+{
-+
-+    FILE * f_cat_rast;
-+    struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
-+    char cat_rast_header[1024];//TODO magic number 
-+    int i_row, i_col, ncols, nrows, cat_rast_col, patch_col, val;
-+    int head_nchars;
-+    int fd_patch_rast, init_shift, step_shift;
-+    unsigned char * patch_data;
-+
-+    char * null_chunk;
-+
-+    //TODO G_free mapset (aslo in compute  scatts)
-+    const char *mapset;
-+
-+    struct Cell_head patch_lines, cat_rast_lines;
-+
-+    unsigned char * row_data;
-+
-+    f_cat_rast = fopen(cat_rast, "rb+");
-+    if(!f_cat_rast)
-+        return -10;
-+
-+
-+    /* 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;
-+    }
-+
-+    Rast_get_cellhd(patch_rast, mapset, &patch_region);
-+    Rast_set_window(&patch_region);
-+            
-+    if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
-+        fclose(f_cat_rast);
-+        return -3;
-+    }
-+
-+    null_chunk =  Rast_allocate_null_buf();
-+
-+    if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
-+
-+    ncols = cat_rast_bounds.east - cat_rast_bounds.west;
-+    nrows = cat_rast_bounds.south - cat_rast_bounds.north;
-+
-+    patch_data = (unsigned char *) G_malloc(ncols * sizeof(unsigned char));
-+
-+    init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
-+
-+    if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
-+        G_message("seek failed");
-+        return -4;
-+    }
-+
-+    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);
-+
-+        for(i_col = 0; i_col < ncols; i_col++) {
-+            patch_col = patch_bounds.west + i_col;
-+
-+            if(null_chunk[patch_col] != 1) 
-+                patch_data[i_col] = 1 & 255;
-+            else {
-+                patch_data[i_col] = 0 & 255;
-+            }
-+        }
-+
-+        fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
-+        if (ferror(f_cat_rast))
-+        {
-+            G_free(null_chunk);
-+            fclose(f_cat_rast);
-+            return -5;
-+        }
-+        if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
-+            G_message("seek failed");
-+            return -6;
-+        }
-+    }
-+
-+    Rast_close(fd_patch_rast);
-+    G_free(null_chunk);
-+    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)
-+{
-+    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunks_pix;
-+    int r_bits = 256;
-+
-+    CELL * band_1_chunks;
-+    CELL * band_2_chunks;
-+    char * band_1_null_chunks,* band_2_null_chunks;
-+
-+    int * scatts_bands = scatts->scatts_bands;
-+    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
-+    {   
-+        band_1_chunks = chunks[scatts_bands[i_scatt * 2]];
-+        band_2_chunks = chunks[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]];
-+
-+        for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+        {
-+            if(!belongs_pix[i_chunks_pix] || 
-+                band_1_null_chunks[i_chunks_pix] == 1 || 
-+                band_2_null_chunks[i_chunks_pix] == 1)                
-+                continue;
-+
-+            array_idx = band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits;
-+
-+            ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
-+        }
-+    }
-+}
-+
-+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)
-+{
-+
-+    int i_chunks_pix, i_cat, i_scatt, n_a_scatts, i_cond;
-+    int cat_id, scatt_plts_cat_idx, array_idx;
-+    char * band_1_null_chunks,* band_2_null_chunks;
-+    
-+    int r_bits = 256;
-+
-+    struct scScatts * scatts_conds;
-+    struct scScatts * scatt_plts_scatts;
-+    struct scdScattData * conds;
-+
-+    int * scatts_bands;
-+    struct scdScattData ** scatts_arr;
-+
-+    CELL * band_1_chunks;
-+    CELL * band_2_chunks;
-+    unsigned int * 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));
-+
-+    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
-+    {
-+        scatts_conds = scatt_conds->cats_arr[i_cat];
-+
-+        cat_id = scatt_conds->cats_ids[i_cat];
-+
-+        scatt_plts_cat_idx = scatt_plts->cats_idxs[cat_id];
-+        if(scatt_plts_cat_idx < 0)
-+            continue;
-+
-+        scatt_plts_scatts = scatt_plts->cats_arr[scatt_plts_cat_idx];
-+
-+        G_zero(belongs_pix, chunk_size * sizeof(unsigned short));
-+
-+        if(!scatts_conds->n_a_scatts && !f_cats_rasts_in[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;
-+            }
-+        }
-+        else
-+        {
-+            scatts_bands = scatts_conds->scatts_bands;
-+
-+            if(f_cats_rasts_in[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]))
-+                {
-+                    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++)
-+                {
-+                    if(rast_pixs[i_chunks_pix] != 0 & 255)
-+                        belongs_pix[i_chunks_pix] = 1;
-+                }
-+
-+            // test every defined conditions in scatter plots
-+            for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
-+            {   
-+                band_1_chunks =  chunks[scatts_bands[i_scatt * 2]];
-+                band_2_chunks =  chunks[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]];
-+
-+                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
-+
-+                for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
-+                {
-+                    if(belongs_pix[i_chunks_pix] || 
-+                       band_1_null_chunks[i_chunks_pix] == 1 || 
-+                       band_2_null_chunks[i_chunks_pix] == 1)
-+                        continue;
-+
-+                    if(i_scatt_conds[band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits])
-+                        belongs_pix[i_chunks_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;
-+
-+            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;
-+            }
-+        }
-+
-+        update_cat_scatt_plt(chunks, null_chunks, chunk_size, belongs_pix, scatt_plts_scatts);
-+    }
-+
-+    G_free(rast_pixs);
-+    G_free(belongs_pix);
-+
-+    return 0;
-+}
-+
-+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
-+    int i_cat, i_scatt, cat_id;
-+
-+    for(i_cat = 0;  i_cat < cats->n_a_cats; i_cat++)
-+    {   
-+        for(i_scatt = 0;  i_scatt < cats->cats_arr[i_cat]->n_a_scatts; i_scatt++)
-+        {   
-+            G_debug(3, "Active scatt %d in catt %d", i_scatt, i_cat);
-+
-+            b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2]] = 1;
-+            b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2 + 1]] = 1;
-+        }
-+    }
-+    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)
-+{
-+    int i, band_id;
-+
-+    for(i = 0; i < (* n_a_bands); i++)
-+    {   
-+        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]);
-+        }
-+    }
-+
-+    if(f_cats_rasts_in)
-+        for(i = 0; i < n_a_cats; i++)
-+            if(f_cats_rasts_in[i])
-+                fclose(f_cats_rasts_in[i]);
-+
-+    if(f_cats_rasts_out)
-+        for(i = 0; i < n_a_cats; i++)
-+            if(f_cats_rasts_out[i])
-+                fclose(f_cats_rasts_out[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)
-+{
-+    int i_cat, id_cat;
-+
-+    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+    {
-+        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;
-+        }
-+        else
-+            f_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)
-+{
-+    int i_cat, id_cat, head_nchars;
-+    char cat_rast_header[1024];//TODO magic number 
-+
-+    head_nchars = get_cat_rast_header(region, cat_rast_header);
-+
-+    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
-+    {
-+        if(!f_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;
-+    }
-+
-+    return head_nchars;
-+
-+}
-+
-+//TODO change name: I_UpdateScattData???
-+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 ||
-+        n_bands != scatt_conds->n_bands)
-+        return -1;
-+
-+    const char *mapset;
-+
-+    FILE * f_cats_rasts_out[scatt_conds->n_a_cats];
-+    FILE * f_cats_rasts_in[scatt_conds->n_a_cats];
-+
-+    CELL * chunks[n_bands];
-+    char * null_chunks[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;
-+    int fd_bands[n_bands];
-+    for(i_band = 0; i_band < n_bands; i_band++)
-+        fd_bands[i_band] = -1;
-+    
-+    int bands_ids[n_bands];
-+    for(i_band = 0; i_band < n_bands; i_band++)
-+        bands_ids[i_band] = -1;
-+
-+    int b_needed_bands[n_bands];  
-+    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]);
-+
-+    Rast_set_window(region);
-+
-+    n_a_bands = 0;/*TODO realy needed?*/
-+    for(id_band = 0; id_band < n_bands; id_band++)
-+    {
-+        if(b_needed_bands[id_band])
-+        {
-+            G_debug(3, "Opening raster no. %d with name: %s", id_band, bands[id_band]);
-+
-+            /* 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, 
-+                                   &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+                return -1;
-+            }
-+            
-+            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, 
-+                                   &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
-+                return -1;
-+            }
-+
-+            //TODO check data type, minimum and maximum value
-+            data_type = Rast_get_map_type(fd_bands[n_a_bands]);
-+            //if(data_type != CELL)
-+            //    return -1;
-+
-+            //What happens if it is not CELL tyoe
-+            chunks[id_band] =  Rast_allocate_c_buf();
-+            null_chunks[id_band] =  Rast_allocate_null_buf();
-+
-+            bands_ids[n_a_bands] = id_band;
-+
-+            ++n_a_bands;
-+        }
-+    }
-+
-+    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;
-+    }
-+
-+    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;
-+    }
-+
-+    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;
-+    }
-+
-+    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);
-+
-+    i_chunk = 0;
-+
-+    nrows = Rast_window_rows();
-+    chunk_size = Rast_window_cols();
-+
-+    for (i_row = 0; i_row < nrows; i_row++)
-+    {
-+        for(i_band = 0; i_band < n_a_bands; i_band++)
-+        {   
-+            band_id = bands_ids[i_band];
-+            G_debug(3, "Reading data for band %d", band_id);
-+            Rast_get_c_row(fd_bands[i_band], chunks[band_id], i_row);
-+            Rast_get_null_value_row (fd_bands[i_band], null_chunks[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) 
-+        {
-+            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], &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 0;    
-+}
-\ No newline at end of file

Copied: sandbox/turek/scatter_plot/testing_patch.diff (from rev 57286, sandbox/turek/scatter_plot/testing_pach.diff)
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	                        (rev 0)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-07-27 01:36:53 UTC (rev 57287)
@@ -0,0 +1,4189 @@
+Index: vector/v.edit/main.c
+===================================================================
+--- vector/v.edit/main.c	(revision 57285)
++++ 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 57285)
++++ include/imagery.h	(working copy)
+@@ -135,6 +135,41 @@
+     
+ } IClass_statistics;
+ 
++/* 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;
++};
++
++struct scdScattData
++{
++    int n_vals;
++    //TODO void pointer???
++    unsigned int  * b_conds_arr;
++    unsigned int  * scatt_vals_arr;
++};
++
+ #define SIGNATURE_TYPE_MIXED 1
+ 
+ #define GROUPFILE "CURGROUP"
+Index: include/defs/vedit.h
+===================================================================
+--- include/defs/vedit.h	(revision 57285)
++++ include/defs/vedit.h	(working copy)
+@@ -34,7 +34,7 @@
+ 
+ /* 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: include/defs/imagery.h
+===================================================================
+--- include/defs/imagery.h	(revision 57285)
++++ include/defs/imagery.h	(working copy)
+@@ -110,6 +110,29 @@
+ 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 I_scd_free_scatt_data(struct scdScattData *);
++int I_scd_get_data_size(struct scdScattData *);
++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 I_create_cat_rast(struct Cell_head *, const char *);
++int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
++
++
+ /* sig.c */
+ int I_init_signatures(struct Signature *, int);
+ int I_new_signature(struct Signature *);
+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,631 @@
++"""!
++ 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
++
++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
++
++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):
++    
++        self.scatts_dt.AddScattPlot(scatt_id = scatt_id)
++
++        scatt_conds = self.scatt_conds_dt.GetData({0 : []})
++        scatts = self.scatts_dt.GetData({0 : [scatt_id]})
++
++        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)
++        self.scatts_dt.SetData(scatts)
++
++    def SetEditCatData(self, cat_id, scatt_id, bbox, value):
++
++        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
++
++        self.ComputeCatScatts([cat_id])
++
++        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)
++        
++        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 = None
++        self.bin_bands_f = []      
++
++        self.region = {}
++
++    def GetRegion(self):
++        return self.region
++
++    def Create(self, bands):
++
++        self.bands = None
++        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.region = self._parseRegion(region)
++
++    def GetBands(self):
++        return self.bands
++
++    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
++
++        self.max_n_cats = 10
++    
++        self.vals = 256 * 256
++
++        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
++
++        if self.type == 0:
++            np_vals = np.zeros(self.vals, dtype = 'uint32')
++        elif self.type == 1:
++            #TODO solve proble with short
++            np_vals = np.zeros(self.vals, dtype = 'uint32')
++        else:
++            return -1
++
++        np_vals.shape = (256, 256)#TODO hack do it general
++
++        self.cats[cat_id][scatt_id] = {
++                                        'np_vals' : np_vals
++                                      }
++
++        return 1
++
++    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']}
++                        
++        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)
++
++        #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] = self.cats[cat_id][scatt_id]['np_vals']
++
++        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 idScattToBands(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 BandsToidScatt(band_1, band_2, n_bands):
++
++    if band_2 <  band_1:
++        tmp = band_1
++        band_1 = band_2
++        band_2 = tmp
++
++
++    n_b1 = n_bands - 1
++
++    scatt_id = (band_1 * (2 * n_b1 + 1) - band_1 * band_1) / 2 + band_2 - band_1 - 1
++
++    return scatt_id
++
+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 @@
++"""!
++ at package scatt_plot.gthreading
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++import os
++import sys
++import time
++import threading
++import Queue
++
++import wx
++from core.gconsole import wxCmdRun, wxCmdDone, wxCmdPrepare
++
++class gThread(threading.Thread):
++    """!Thread for GRASS commands"""
++    requestId = 0
++
++    def __init__(self, receiver, requestQ=None, resultQ=None, **kwds):
++        """!
++        @param receiver event receiver (used in PostEvent)
++        """
++        threading.Thread.__init__(self, **kwds)
++
++        if requestQ is None:
++            self.requestQ = Queue.Queue()
++        else:
++            self.requestQ = requestQ
++
++        if resultQ is None:
++            self.resultQ = Queue.Queue()
++        else:
++            self.resultQ = resultQ
++
++        self.setDaemon(True)
++
++        self.receiver = receiver
++        self._want_abort_all = False
++
++        self.start()
++
++    def Run(self, *args, **kwds):
++        """!Run command in queue
++
++        @param args unnamed command arguments
++        @param kwds named command arguments
++
++        @return request id in queue
++        """
++        gThread.requestId += 1
++        self.requestQ.put((gThread.requestId, args, kwds))
++
++        return gThread.requestId
++
++    def GetId(self):
++         """!Get id for next command"""
++         return gThread.requestId + 1
++
++    def SetId(self, id):
++        """!Set starting id"""
++        gThread.requestId = id
++
++    def run(self):
++        os.environ['GRASS_MESSAGE_FORMAT'] = 'gui'
++        while True:
++            requestId, args, kwds = self.requestQ.get()
++            for key in ('callable', 'onDone', 'onPrepare', 'userData'):
++                if key in kwds:
++                    vars()[key] = kwds[key]
++                    del kwds[key]
++                else:
++                    vars()[key] = None
++
++            requestTime = time.time()
++
++            #if self._want_abort_all and self.requestCmd is not None:
++            #    self.requestCmd.abort()
++            #    if self.requestQ.empty():
++            #        self._want_abort_all = False
++
++            # prepare
++            if self.receiver:
++                event = wxCmdPrepare(type = 'method',
++                                     time=requestTime,
++                                     pid=requestId)
++
++                wx.PostEvent(self.receiver, event)
++
++                # run command
++                event = wxCmdRun(type = 'method',
++                                 pid=requestId)
++
++                wx.PostEvent(self.receiver, event)
++
++            time.sleep(.1)
++
++            ret = None
++            exception = None
++            #try:
++            ret = vars()['callable'](*args, **kwds)
++            #except Exception as e:
++            #    exception  = e;
++
++            self.resultQ.put((requestId, ret))
++
++            time.sleep(.1)
++
++          
++            if self.receiver:
++                event = wxCmdDone(type = 'cmd',
++                                  kwds = kwds,
++                                  args = args, #TODO expand args to kwds
++                                  ret=ret,
++                                  exception=exception,
++                                  pid=requestId)
++
++                # send event
++                wx.PostEvent(self.receiver, event)
++
++    def abort(self, abortall=True):
++        """!Abort command(s)"""
++        if abortall:
++            self._want_abort_all = True
++        if self.requestQ.empty():
++            self._want_abort_all = False
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/dialogs.py
+===================================================================
+--- gui/wxpython/scatt_plot/dialogs.py	(revision 0)
++++ gui/wxpython/scatt_plot/dialogs.py	(working copy)
+@@ -0,0 +1,612 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++import wx.lib.mixins.listctrl as listmix
++import wx.lib.flatnotebook  as FN
++import wx.aui
++
++from core          import globalvar
++from core.gcmd     import GException, GError, RunCommand
++
++from gui_core.gselect import Select
++from 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, BandsToidScatt
++from scatt_plot.plots       import ScatterPlotWidget
++
++
++class ScattPlotMainDialog(wx.Dialog):
++    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))
++
++        #TODO remove iclass parameter
++        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)
++
++        # Fancy gui
++        self._mgr = wx.aui.AuiManager(self)
++        self._addPanes()
++        self._mgr.Update()
++
++        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)
++
++        dlgSize = (220, 400)
++        self.SetMinSize(dlgSize)
++        self.SetInitialSize(dlgSize)
++
++        #fix goutput's pane size (required for Mac OSX)
++        #if self.gwindow:         
++        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++
++    def _doLayout(self):
++
++        sizer = wx.BoxSizer(wx.VERTICAL)
++
++        sizer.Add(item = self.notebook, proportion = 1,
++                  flag = wx.EXPAND)
++
++        self.mainPanel.SetSizer(sizer)
++
++        sizer.Fit(self)  
++        self.Layout()
++
++    #TODO split to panel?
++    def _createCategoryPage(self):
++        catsPanel = wx.Panel(parent = self)
++
++
++        self.notebook.AddPage(page = catsPanel, 
++                              text=_('Categories'), 
++                              name = 'categories')
++
++        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)
++
++        AnalysisSizer = wx.BoxSizer(wx.VERTICAL)
++
++        catsSizer = wx.BoxSizer(wx.VERTICAL)
++
++        catsSizer.Add(item = self.toolbars['catsList'], proportion = 0)
++        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND)
++
++        catsPanel.SetSizer(catsSizer)
++
++    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))
++
++        self._mgr.AddPane(self.mainPanel,
++                              wx.aui.AuiPaneInfo().
++                              Name("tabs").CaptionVisible(visible = False).
++                              Center().
++                              Dockable(False).
++                              CloseButton(False).Layer(0))
++
++    def OnCloseDialog(self, event):
++        """!Close dialog"""
++        self.scatt_mgr.CleanUp()
++        self.Destroy()
++
++    def OnSettings(self, event):
++        pass
++
++    def OnSetData(self, event):
++
++        dlg = SetDataDialog(parent=self)        
++
++        if dlg.ShowModal() == wx.ID_OK:
++            bands = dlg.GetBands()
++            self.scatt_mgr.SetData(bands)
++        
++        dlg.Destroy()
++
++
++    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()
++
++    def OnSettings(self, event):
++        pass
++
++    def OnAddScattPl(self, event):
++
++        bands = self.scatt_mgr.GetBands()
++        if not bands:
++            GError(_('No data set for scatter plot.'))
++            return
++
++        dlg = AddScattPlotDialog(parent = self, bands = bands)
++        
++        if dlg.ShowModal() == wx.ID_OK:
++            self.scatt_mgr.AddScattPlot(dlg.GetScattId())
++        
++        dlg.Destroy()
++
++    def EditCatAdd(self):
++        self._setEditCat(tool_name = 'editCatAdd')
++
++    def EditCatRemove(self):
++        self._setEditCat(tool_name = 'editCatRemove')
++
++    def _setEditCat(self, tool_name):
++        
++        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.edit_cat_tools[i_tool_name]['toggle'] = False
++
++                toolbar = self.toolbars['catsList']
++                toolbar.ToggleTool(vars(toolbar)[i_tool_name], False)
++            
++            self.edit_cat_tools[tool_name]['toggle'] = True
++            self.scatt_mgr.EditCat(edit_type = self.edit_cat_tools[tool_name]['type'])
++            return
++
++        self.scatt_mgr.EditCat(edit_type = None)
++        self.edit_cat_tools[tool_name]['toggle'] = False
++
++    def GetScattMgr(self):
++        return  self.scatt_mgr
++
++
++class SetDataDialog(wx.Dialog):
++
++    def __init__(self, parent, id  = wx.ID_ANY):
++        
++        wx.Dialog.__init__(self, parent, title = ("Select imagery group "), id = id)
++
++        self.bands = []
++
++
++        self._createWidgets()
++        self.group.SetValue("testovaci_1")
++
++    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.group = Select(parent = self, type = 'group',
++                            size = globalvar.DIALOG_GSELECT_SIZE)
++
++        # buttons
++        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++        
++        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++        self._layout()
++
++    def _layout(self):
++
++        border = wx.BoxSizer(wx.VERTICAL) 
++        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.group_label, 
++                                                    sel = self.group))
++
++        # buttons
++        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++        self.btnsizer.Add(item = self.btn_close, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++        
++        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++
++        dialogSizer.Add(item = self.btnsizer, proportion = 0,
++                        flag = wx.ALIGN_CENTER)
++
++        border.Add(item = dialogSizer, proportion = 0,
++                   flag = wx.ALL, border = 5)
++
++        self.SetSizer(border)
++        self.Layout()
++        self.Fit()
++
++        # bindings
++        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++    def _addSelectSizer(self, title, sel): 
++        """!Helper layout function.
++        """
++        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++        selTitleSizer.Add(item = title, proportion = 1,
++                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++        selSizer.Add(item = selTitleSizer, proportion = 0,
++                     flag = wx.EXPAND)
++
++        selSizer.Add(item = sel, proportion = 1,
++                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++                     border = 5)
++
++        return selSizer
++
++    def GetBands(self):
++
++        return self.bands
++
++    def OnClose(self, event):
++        """!Close dialog
++        """
++        if not self.IsModal():
++            self.Destroy()
++        event.Skip()
++
++    def OnOk(self, event):
++        """!
++        """
++        ret, stdout, err_msg = RunCommand("i.group",
++                                      getErrorMsg = True,
++                                      read = True,
++                                      quiet = True,
++                                      group = self.group.GetValue().strip(),
++                                      flags = 'g')
++
++        if ret != 0:
++            GError("%s module failed:\n%s" % ("<i.group>", err_msg))
++            return
++
++        self.bands = stdout.split('\n')
++
++        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()
++
++class AddScattPlotDialog(wx.Dialog):
++
++    def __init__(self, parent, bands, id  = wx.ID_ANY):
++        
++        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++        self.bands = bands
++
++        self.scatt_id = None
++
++        self._createWidgets()
++
++    def _createWidgets(self):
++
++        self.labels = {}
++        self.params = {}
++
++        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        # buttons
++        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++        
++        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++        self._layout()
++
++    def _layout(self):
++
++        border = wx.BoxSizer(wx.VERTICAL) 
++        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
++                                                    sel = self.band_1_ch))
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
++                                                    sel = self.band_2_ch))
++
++        # buttons
++        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++        self.btnsizer.Add(item = self.btn_close, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++        
++        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++
++        dialogSizer.Add(item = self.btnsizer, proportion = 0,
++                        flag = wx.ALIGN_CENTER)
++
++        border.Add(item = dialogSizer, proportion = 0,
++                   flag = wx.ALL, border = 5)
++
++        self.SetSizer(border)
++        self.Layout()
++        self.Fit()
++
++        # bindings
++        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++    def _addSelectSizer(self, title, sel): 
++        """!Helper layout function.
++        """
++        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++        selTitleSizer.Add(item = title, proportion = 1,
++                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++        selSizer.Add(item = selTitleSizer, proportion = 0,
++                     flag = wx.EXPAND)
++
++        selSizer.Add(item = sel, proportion = 1,
++                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++                     border = 5)
++
++        return selSizer
++
++    def OnClose(self, event):
++        """!Close dialog
++        """
++        if not self.IsModal():
++            self.Destroy()
++        event.Skip()
++
++    def OnOk(self, event):
++        """!
++        """
++        band_1 = self.band_1_ch.GetSelection()
++        band_2 = self.band_2_ch.GetSelection()
++
++
++        if band_1 == band_2:
++            GError(_("Selected bands must be different."))
++            return
++        
++        #TODO axes selection
++        if band_1 > band_2:
++            tmp_band = band_2
++            band_2 = band_1
++            band_1 = band_2
++
++        self.scatt_id = BandsToidScatt(band_1, band_2, len(self.bands))
++
++        event.Skip()
++
++    def GetScattId(self):
++        return self.scatt_id
++
++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)
++
++    def GetPlot(self):
++        return self.scatt
++
++    def _doLayout(self):
++        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
++        self.main_sizer.Add(self.self)
++
++        self.panel.SetSizer(self.main_sizer)
++        self.main_sizer.Fit(self)
++    
++    def OnPlotClosed(self, scatt_id):
++        self.Destroy()
++
++class CategoryListCtrl(wx.ListCtrl,
++                       listmix.ListCtrlAutoWidthMixin,
++                       listmix.TextEditMixin):
++
++    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++
++        wx.ListCtrl.__init__(self, parent, id,
++                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++        self.columns = ((_('Category name'), 'name'),
++                        (_('Color'), 'color'))
++        self.Populate(columns = self.columns)
++        
++        self.cats_mgr = cats_mgr
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++        self.rightClickedItemIdx = wx.NOT_FOUND
++        
++        listmix.ListCtrlAutoWidthMixin.__init__(self)
++
++        listmix.TextEditMixin.__init__(self)
++        
++        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
++        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
++             
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++        self.cats_mgr.deletedCategory.connect(self.Update)
++        self.cats_mgr.addedCategory.connect(self.Update)
++
++    def Update(self, **kwargs):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def InitCoreCats(self):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def SetVirtualData(self, row, column, text):
++        attr = self.columns[column][1]
++        if attr == 'name':
++            try:
++                text.encode('ascii')
++            except UnicodeEncodeError:
++                GMessage(parent = self, message = _("Please use only ASCII characters."))
++                return
++
++        cat_id = self.cats_mgr.GetCategories()[row]
++
++        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
++        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++        
++        self.Select(row)
++        
++    def Populate(self, columns):
++        for i, col in enumerate(columns):
++            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++
++        self.SetColumnWidth(0, 100)
++        self.SetColumnWidth(1, 100)
++        
++    def AddCategory(self):
++
++        self.cats_mgr.addedCategory.disconnect(self.Update)
++        cat_id = self.cats_mgr.AddCategory()
++        self.cats_mgr.addedCategory.connect(self.Update)
++
++        if cat_id < 0:
++            GError(_("Maximum limit of categories number was reached."))
++            return
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++                        
++    def DeleteCategory(self):
++        indexList = sorted(self.GetSelectedIndices(), reverse = True)
++        cats = []
++        for i in indexList:
++            # remove temporary raster
++            cat_id = self.cats_mgr.GetCategories()[i]
++            
++            cats.append(cat_id)
++
++            self.cats_mgr.deletedCategory.disconnect(self.Update)
++            self.cats_mgr.DeleteCategory(cat_id)
++            self.cats_mgr.deletedCategory.connect(self.Update)
++            
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        
++    def OnSel(self, event): 
++        self.cats_mgr.SetSelectedCat(event.GetIndex() + 1)
++
++        event.Skip()
++
++    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
++        indices = []
++        lastFound = -1
++        while True:
++            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
++            if index == -1:
++                break
++            else:
++                lastFound = index
++                indices.append(index)
++        return indices        
++
++    def OnEdit(self, event):
++        currentItem = event.m_itemIndex
++        currentCol = event.m_col
++
++        if currentCol == 1:
++            dlg = wx.ColourDialog(self)
++            dlg.GetColourData().SetChooseFull(True)
++
++            if dlg.ShowModal() == wx.ID_OK:
++                color = dlg.GetColourData().GetColour().Get()
++                color = ':'.join(map(str, color))
++                self.SetVirtualData(currentItem, currentCol, color)
++            dlg.Destroy()
++            wx.CallAfter(self.SetFocus)
++        
++        event.Skip()
++        
++        
++    def DeselectAll(self):
++        """!Deselect all items"""
++        indexList = self.GetSelectedIndices()
++        for i in indexList:
++            self.Select(i, on = 0)
++         
++        # no highlight
++        self.OnCategorySelected(None)
++        
++    def OnGetItemText(self, item, col):
++        attr = self.columns[col][1]
++        cat_id = self.cats_mgr.GetCategories()[item]
++
++        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
++
++    def OnGetItemImage(self, item):
++        return -1
++
++    def OnGetItemAttr(self, item):
++        return None
+Index: gui/wxpython/scatt_plot/toolbars.py
+===================================================================
+--- gui/wxpython/scatt_plot/toolbars.py	(revision 0)
++++ gui/wxpython/scatt_plot/toolbars.py	(working copy)
+@@ -0,0 +1,106 @@
++"""!
++ at package scatt_plot.toolbars
++
++ at brief Scatter plot - toolbars
++
++Classes:
++ - toolbars::MainToolbar
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++
++
++import wx
++
++from icons.icon        import MetaIcon
++from gui_core.toolbars import BaseToolbar, BaseIcons
++from core.gcmd         import RunCommand
++
++class MainToolbar(BaseToolbar):
++    """!Main toolbar
++    """
++    def __init__(self, parent):
++        BaseToolbar.__init__(self, parent)
++        
++        self.InitToolbar(self._toolbarData())
++        
++        # realize the toolbar
++        self.Realize()
++
++    def _toolbarData(self):
++
++        icons = {
++                 'set_data'    : MetaIcon(img = 'layer-raster-add',
++                                         label = _('Set input raster data for plots')),
++                 'settings'   : BaseIcons['settings'].SetLabel( _('Ssettings')),
++                 'help'       : MetaIcon(img = 'help',
++                                         label = _('Show manual')),
++                 'add_scatt_pl'  : MetaIcon(img = 'layer-raster-analyze',
++                                            label = _('Add scatter plot'))
++                }
++
++        return self._getToolbarData((
++                                     ('sat_data', icons["set_data"],
++                                      self.parent.OnSetData),
++                                     (None, ),
++                                     ('add_scatt', icons["add_scatt_pl"],
++                                      self.parent.OnAddScattPl),
++                                     #('settings', icons["settings"],
++                                     # self.parent.OnSettings),  
++                                     #('help', icons["help"],
++                                     # self.OnHelp),                    
++                                     ("quit", BaseIcons['quit'],
++                                      self.parent.OnCloseDialog)
++                                    ))
++
++    def OnHelp(self, event) :
++            RunCommand('g.manual',
++                       entry = 'wxGUI.scatt_plot')
++
++class CategoriesToolbar(BaseToolbar):
++
++    def __init__(self, parent, cats_list, scatts_dlg):
++        BaseToolbar.__init__(self, parent)
++        self.cats_list = cats_list
++        self.scatts_dlg = scatts_dlg
++
++        self.InitToolbar(self._toolbarData())
++        
++
++        # realize the toolbar
++        self.Realize()
++
++
++    def _toolbarData(self):
++
++        icons = {
++            'editCatAdd'  : MetaIcon(img = 'polygon-create',
++                                     label = _('Add region to category mode')),
++            'editCatRemove'  : MetaIcon(img = 'polygon-delete',
++                                        label = _('Remove region to category mode')),
++            'addCat'     : MetaIcon(img = 'layer-add',
++                                    label = _('Add category')),
++            'deleteCat'  : MetaIcon(img = 'layer-remove',
++                                    label = _('Delete category'))
++            }
++
++        return  self._getToolbarData((('editCatAdd', icons['editCatAdd'],
++                                        lambda event: self.scatts_dlg.EditCatAdd(),
++                                        wx.ITEM_CHECK),
++                                      ('editCatRemove', icons['editCatRemove'],
++                                        lambda event: self.scatts_dlg.EditCatRemove(),
++                                        wx.ITEM_CHECK),
++                                     (None, ),
++                                     ('addCat', icons["addCat"],
++                                        lambda event: self.cats_list.AddCategory()),
++                                     ('deleteCat', icons["deleteCat"],
++                                        lambda event: self.cats_list.DeleteCategory())))
++                                    
++    def GetToolId(self, toolName): #TODO can be useful in base
++
++        return vars(self)[toolName]            
+\ No newline at end of file
+Index: gui/wxpython/scatt_plot/core_c.py
+===================================================================
+--- gui/wxpython/scatt_plot/core_c.py	(revision 0)
++++ gui/wxpython/scatt_plot/core_c.py	(working copy)
+@@ -0,0 +1,211 @@
++"""!
++ at package scatt_plot.scatt_plot
++
++ at brief Functions which work with scatter plot c code.
++
++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)
++"""
++
++from multiprocessing import Process, Queue
++
++from ctypes import *
++try:
++    from grass.lib.imagery import *
++    from grass.lib.gis import Cell_head, G_get_window
++
++except ImportError, e:
++    sys.stderr.write(_("Loading imagery lib failed"))
++
++def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out):
++
++    #return _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out)
++
++    # Queue object for interprocess communication
++    q = Queue()
++
++    # The separate render process
++    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
++                                                    n_bands, scatts, cats_rasts_in, cats_rasts_out, q))
++    p.start()
++    ret = q.get()
++    p.join()
++
++    return ret[0], ret[1]
++
++def UpdateCatRast(patch_rast, region, cat_rast):
++
++    #return ComputeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts)
++    # Queue object for interprocess communication
++
++    #_updateCatRastProcess(patch_rast, region, cat_rast, None)
++    #return 
++    q = Queue()
++    # The separate render process
++    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
++    p.start()
++    #ret = q.get()
++    p.join()
++
++    #return ret[0], ret[1]
++
++def CreateCatRast(region, cat_rast):
++
++    cell_head = _regionToCellHead(region)
++    I_create_cat_rast(pointer(cell_head), cat_rast)   
++
++def _computeScattsProcess(region, scatt_conds, bands, n_bands, scatts, cats_rasts_in, cats_rasts_out, output_queue):
++
++    #TODO names for types not 0 and 1?
++    sccats_c, vals_dt = _getComputationStruct(scatts, 0, n_bands)
++    scatt_conds_c, vals_dt2 = _getComputationStruct(scatt_conds, 1, n_bands)
++
++    char_bands = _stringListToCharArr(bands)
++    char_cats_rasts_out = _stringListToCharArr(cats_rasts_out)
++    char_cats_rasts_in = _stringListToCharArr(cats_rasts_in)
++
++    cell_head = _regionToCellHead(region)
++
++    ret = I_compute_scatts(pointer(cell_head),
++                          pointer(scatt_conds_c),
++                          pointer(char_bands),
++                          n_bands,
++                          pointer(sccats_c),
++                          pointer(char_cats_rasts_in),
++                          pointer(char_cats_rasts_out))
++
++    I_sc_free_cats(pointer(sccats_c))
++    I_sc_free_cats(pointer(scatt_conds_c))
++
++    output_queue.put((ret, scatts))
++    #return (ret, scatts)
++
++def _regionToCellHead(region):
++    cell_head = struct_Cell_head()
++    G_get_window(pointer(cell_head))
++
++    convert_dict = {'n' : 'north', 'e' : 'east', 
++                    'w' : 'west',  's' : 'south', 
++                    'nsres' : 'ns_res',
++                    'ewres' : 'ew_res'}
++
++    for k, v in region.iteritems():
++        if k in ["rows", "cols", "cells"]:
++            v = int(v)
++        else:
++            v = float(v)
++
++        if convert_dict.has_key(k):
++            k = convert_dict[k]
++           
++        setattr(cell_head, k, v)
++
++    return cell_head
++
++def _stringListToCharArr(str_list):
++
++    arr = c_char_p * len(str_list)
++    char_arr = arr()
++    for i, st in enumerate(str_list):
++        if st:
++            char_arr[i] = st
++        else:
++            char_arr[i] = None
++
++    return char_arr
++
++def _getComputationStruct(cats, cats_type, n_bands):
++
++    sccats = struct_scCats()
++    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
++        
++    #for i in range(sccats.n_a_cats):
++    #    cat_id = sccats.cats_ids[i]
++    #    I_sc_delete_cat(pointer(sccats), cat_id)
++    #    i -= 1
++
++    vals_dt = []
++    for cat_id, scatt_ids in cats.iteritems():
++        I_sc_add_cat(pointer(sccats), cat_id)
++
++        for scatt_id, dt in scatt_ids.iteritems():
++            # if key is missing condition is always True (full scatter plor is computed)
++            if cats[cat_id].has_key(scatt_id):
++
++                vals = dt["np_vals"]
++                #TODO hack
++                vals.shape = (256 * 256)
++
++                c_uint_p = ctypes.POINTER(ctypes.c_uint)
++                scatt_vals = scdScattData()
++                if cats_type == 0:
++                    vals[:] = 0
++                    scatt_vals.scatt_vals_arr = vals.ctypes.data_as(c_uint_p)
++
++                else:
++                    #TODO solve proble with short integer
++                    scatt_vals.b_conds_arr = vals.ctypes.data_as(c_uint_p)
++
++                vals_dt.append(scatt_vals)
++
++                #vals_dt.append(data_p)
++                vals.shape = (256, 256)
++                I_sc_insert_scatt_data(pointer(sccats),  
++                                       pointer(scatt_vals),
++                                       cat_id, scatt_id)
++
++    return sccats, vals_dt
++
++def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
++
++    #TODO names for types not 0 and 1?
++
++    cell_head = _regionToCellHead(region)
++    
++    
++    cat_rast
++    I_insert_patch_to_cat_rast(patch_rast, 
++                                     pointer(cell_head), 
++                                     cat_rast)
++
++    #print re
++    #output_queue.put((ret, scatts))
++    #return (ret, scatts)
++
++"""
++class A:
++    def __init__(self):        
++        self.i = 0        
++
++    def incr(self):
++        self.i += 1
++        return self.i
++
++def worker(input, output):
++    print "ahoj"
++    for func, args in iter(input.get, 'STOP'):
++        print "jedu"
++        result = func.incr
++        output.put(result)
++
++def test():
++    # Create queues
++    task_queue = Queue()
++    done_queue = Queue()
++
++    # Start worker processes
++    a = A()
++
++    prc = Process(target=worker, args=(task_queue, done_queue)).start()
++    task_queue.put((a,1))
++
++    data = done_queue.get()
++    print data
++    task_queue.put('STOP')
++"""
+Index: gui/wxpython/scatt_plot/__init__.py
+===================================================================
+--- gui/wxpython/scatt_plot/__init__.py	(revision 0)
++++ gui/wxpython/scatt_plot/__init__.py	(working copy)
+@@ -0,0 +1,8 @@
++all = [
++    'dialogs',
++    'gthreading',
++    'plots',
++    'sc_pl_core',
++    'toolbars',
++    'core_c',
++    ]
+Index: gui/wxpython/scatt_plot/plots.py
+===================================================================
+--- gui/wxpython/scatt_plot/plots.py	(revision 0)
++++ gui/wxpython/scatt_plot/plots.py	(working copy)
+@@ -0,0 +1,185 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief Ploting widgets.
++
++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 wx
++import numpy as np
++import random
++try:
++    haveMatPlot = True
++    import matplotlib
++    matplotlib.use('WXAgg')
++    from matplotlib.figure import Figure
++    from matplotlib.backends.backend_wxagg import \
++    FigureCanvasWxAgg as FigCanvas, \
++    NavigationToolbar2WxAgg as NavigationToolbar
++except ImportError:
++    haveMatPlot = False
++
++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
++
++        self._createWidgets()
++        self._doLayout()
++        self.scatt_id = scatt_id
++        self.scatt_mgr = scatt_mgr
++        self.press_coords = None
++
++        self.cidpress = None
++        self.cidrelease = None
++
++    def StartCategoryEdit(self):
++        'connect to all the events we need'
++        self.cidpress = self.canvas.mpl_connect(
++            'button_press_event', self.OnPress)
++        self.cidrelease = self.canvas.mpl_connect(
++            'button_release_event', self.OnRelease)
++        #self.cidmotion = self.canvas.mpl_connect(
++        #    'motion_notify_event', self.OnRelease)
++
++    def OnPress(self, event):
++        'on button press we will see if the mouse is over us and store some data'
++
++        if event.xdata and event.ydata:
++            self.press_coords = { 'x' : event.xdata, 'y' : event.ydata}
++        else:
++            self.press_coords = None
++
++    def OnRelease(self, event):
++        'on release we reset the press data'
++
++        if event.xdata and event.ydata and self.press_coords:
++
++            bbox = {}
++            if event.ydata > self.press_coords['y']:
++                bbox['up_y'] = event.ydata
++                bbox['btm_y'] = self.press_coords['y']
++            else:
++                bbox['up_y'] = self.press_coords['y']
++                bbox['btm_y'] = event.ydata
++
++            if event.xdata > self.press_coords['x']:
++                bbox['up_x'] = event.xdata
++                bbox['btm_x'] = self.press_coords['x']
++            else:
++                bbox['up_x'] = self.press_coords['x']
++                bbox['btm_x'] = event.xdata
++
++            self.scatt_mgr.SetEditCatData(self.scatt_id, bbox)
++
++    def StopCategoryEdit(self):
++        'disconnect all the stored connection ids'
++
++        if self.cidpress:
++            self.canvas.mpl_disconnect(self.cidpress)
++        if self.cidrelease:
++            self.canvas.mpl_disconnect(self.cidrelease)
++        #self.canvas.mpl_disconnect(self.cidmotion)
++
++    def _createWidgets(self):
++
++        # Create the mpl Figure and FigCanvas objects. 
++        # 5x4 inches, 100 dots-per-inch
++        #
++        self.dpi = 100
++        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
++        self.canvas = FigCanvas(self, -1, self.fig)
++        
++        # Since we have only one plot, we can use add_axes 
++        # instead of add_subplot, but then the subplot
++        # configuration tool in the navigation toolbar wouldn't
++        # work.
++        #
++        self.axes = self.fig.add_subplot(111)
++        
++        # Bind the 'pick' event for clicking on one of the bars
++        #
++        self.canvas.mpl_connect('button_press_event', self.on_pick)
++        
++
++        # Create the navigation toolbar, tied to the canvas
++        #
++        self.toolbar = NavigationToolbar(self.canvas)
++        
++    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.SetSizer(self.main_sizer)
++        self.main_sizer.Fit(self)
++    
++    def Plot(self, scatts, styles):
++        """ Redraws the figure
++        """
++      
++        self.axes.clear()
++        for cat_id, cat in scatts.iteritems():
++            if cat_id == 0:
++                cmap = matplotlib.cm.jet
++                cmap.set_bad('w',1.)
++                cmap._init()
++                cmap._lut[len(cmap._lut) - 1, -1] = 0
++            else:
++                colors = styles[cat_id]['color'].split(":")
++
++                cmap = matplotlib.cm.jet
++                cmap.set_bad('w',1.)
++                cmap._init()
++                cmap._lut[len(cmap._lut) - 1, -1] = 0
++                cmap._lut[:, 0] = int(colors[0])/255.0
++                cmap._lut[:, 1] = int(colors[1])/255.0
++                cmap._lut[:, 2] = int(colors[2])/255.0
++
++            masked_cat = np.ma.masked_less_equal(cat, 0)
++
++            self.axes.imshow(masked_cat, cmap = cmap,  interpolation='nearest')
++
++            self.canvas.draw()
++    
++    def on_pick(self, event):
++        pass
++        # The event received here is of the type
++        # matplotlib.backend_bases.PickEvent
++        #
++        # It carries lots of information, of which we're using
++        # only a small amount here.
++        # 
++        #box_points = event.x
++        
++        #msg = "You've clicked on a bar with coords:\n"
++        
++        #dlg = wx.MessageDialog(
++        #    self, 
++        #    msg, 
++        #    "Click!",
++        #    wx.OK | wx.ICON_INFORMATION)
++
++        #dlg.ShowModal() 
++        #dlg.Destroy()        
++
++    def on_exit(self, event):
++            
++        self.CleanUp()
++        
++    def CleanUp(self):
++        
++        self.parent.OnPlotClosed(self.scatt_id)
++        self.Destroy()
+\ No newline at end of file
+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,513 @@
++"""!
++ 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, BandsToidScatt
++
++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
++
++        wx.EvtHandler.__init__(self)
++        self.giface = giface
++        self.mapDisp  = giface.GetMapDisplay()
++        self.mapWin = giface.GetMapWindow()
++
++        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)
++        else:
++            self.mapWin_conn = None
++            self.iclass_conn = None
++
++        self.tasks_pids = {
++                            'add_scatt' : -1,
++                            'set_data' : -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
++        self.tasks_pids['set_data'] = self.thread.GetId()
++        self.thread.Run(callable = self.core.SetData, bands = bands)
++
++    def SetDataDone(self, event):
++        self.data_set = True
++        self.cats_mgr.InitCoreCats()
++
++    def OnOutput(self, event):
++        """!Print thread output according to debug level.
++        """
++        print event.text
++
++    def GetBands(self):
++        return self.core.GetBands()
++
++    def AddScattPlot(self, scatt_id):
++
++        self.tasks_pids['add_scatt'] = 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)
++
++        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.ComputeCatScatts, 
++                                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 self.tasks_pids['add_scatt'] == event.pid:
++            self.AddScattPlotDone(event)
++            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 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/vdigit/wxdigit.py
+===================================================================
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57285)
++++ gui/wxpython/vdigit/wxdigit.py	(working copy)
+@@ -17,7 +17,7 @@
+ (and NumPy would be an excellent candidate for acceleration via
+ e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
+ 
+-(C) 2007-2011 by the GRASS Development Team
++(C) 2007-2011, 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.
+@@ -27,6 +27,8 @@
+ 
+ import grass.script.core as grass
+ 
++from grass.pydispatch.signal import Signal
++
+ from core.gcmd        import GError
+ from core.debug       import Debug
+ from core.settings    import UserSettings
+@@ -176,7 +178,17 @@
+         
+         if self.poMapInfo:
+             self.InitCats()
+-        
++
++        #TODO signal for errors?
++        self.featureAdded = Signal('IVDigit.featureAdded')
++        self.areasDeleted = Signal('IVDigit.areasDeleted')
++        self.vertexMoved = Signal('IVDigit.vertexMoved')
++        self.vertexAdded = Signal('IVDigit.vertexAdded')
++        self.vertexRemoved = Signal('IVDigit.vertexRemoved')
++        self.featuresDeleted = Signal('IVDigit.featuresDeleted')
++        self.featuresMoved = Signal('IVDigit.featuresMoved')
++        self.lineEdited = Signal('IVDigit.lineEdited')
++
+     def __del__(self):
+         Debug.msg(1, "IVDigit.__del__()")
+         Vect_destroy_line_struct(self.poPoints)
+@@ -394,7 +406,6 @@
+         
+         @return tuple (number of added features, feature ids)
+         """
+-        
+         layer = self._getNewFeaturesLayer()
+         cat = self._getNewFeaturesCat()
+         
+@@ -419,10 +430,14 @@
+             return (-1, None)
+         
+         self.toolbar.EnableUndo()
+-        
+-        return self._addFeature(vtype, points, layer, cat,
+-                                self._getSnapMode(), self._display.GetThreshold())
+-    
++
++        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]})
++
++        return ret
++
+     def DeleteSelectedLines(self):
+         """!Delete selected features
+ 
+@@ -434,16 +449,25 @@
+         # colect categories for delete if requested
+         deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
+         catDict = dict()
++
++        old_geoms = []
++        old_areas_cats = []
+         if deleteRec:
+             for i in self._display.selected['ids']:
++                
+                 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))
++                
+                 cats = self.poCats.contents
+-                for j in range(cats.n_cats):
+-                    if cats.field[j] not in catDict.keys():
+-                        catDict[cats.field[j]] = list()
+-                    catDict[cats.field[j]].append(cats.cat[j])
++
++                # catDict was not used -> put into comment
++                #for j in range(cats.n_cats):
++                #    if cats.field[j] not in catDict.keys():
++                #        catDict[cats.field[j]] = list()
++                #    catDict[cats.field[j]].append(cats.cat[j])
+         
+         poList = self._display.GetSelectedIList()
+         nlines = Vedit_delete_lines(self.poMapInfo, poList)
+@@ -456,7 +480,8 @@
+                 self._deleteRecords(cats)
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++            self.featuresDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)
++
+         return nlines
+             
+     def _deleteRecords(self, cats):
+@@ -512,22 +537,123 @@
+ 
+         @return number of deleted 
+         """
++        if len(self._display.selected['ids']) < 1:
++            return 0
++        
+         poList = self._display.GetSelectedIList()
+         cList  = poList.contents
+         
+         nareas = 0
++        old_geoms = []
++        old_areas_cats = []
++
+         for i in range(cList.n_values):
++
+             if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
+                 continue
+-            
++
++            area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
++            if area > 0: 
++                geoms, cats = self._getaAreaGeomsCats(area)
++                old_geoms += geoms
++                old_areas_cats += cats
++
+             nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
+         
+         if nareas > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
++            self.areasDeleted.emit(old_geoms = old_geoms, old_areas_cats = old_areas_cats)        
++
++        return nareas
++   
++
++    def _getaAreaGeomsCats(self, area):
++
++        po_b_list = Vect_new_list()
++        Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
++        b_list = po_b_list.contents
++
++        geoms = []
++        areas_cats = []
++
++        if b_list.n_values > 0:
++            for i_line in  range(b_list.n_values):
++
++                line = b_list.value[i_line];
++
++                geoms.append(self._getGeom(abs(line)))
++                areas_cats.append(self._getLineAreasCategories(abs(line)))
+         
+-        return nareas
++        Vect_destroy_list(po_b_list);
++
++        return geoms, areas_cats
++
++    def _getLineAreasCategories(self, ln_id):
++
++        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
++        if ltype != GV_BOUNDARY:
++            return []
++
++        cats = [None, None]
++
++        left = c_int()
++        right = c_int()
++
++        if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
++            areas = [left.value, right.value]
++
++            for i, a in enumerate(areas):
++                if a > 0: 
++                    centroid = Vect_get_area_centroid(self.poMapInfo, a)
++                    if centroid <= 0:
++                        continue
++                    c = self._getCategories(centroid)
++                    if c:
++                        cats[i] = c
++
++        return cats
++
++    def _getCategories(self, ln_id):
++        
++        poCats = Vect_new_cats_struct()
++        if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
++            Vect_destroy_cats_struct(poCats)
++            return None
++
++        cCats = poCats.contents
++
++        cats = {}
++        for j in range(cCats.n_cats):
++            if cats.has_key(cCats.field[j]):
++                cats[cCats.field[j]].append(cCats.cat[j])
++            else:
++                cats[cCats.field[j]] = [cCats.cat[j]]
+     
++        Vect_destroy_cats_struct(poCats)
++        return cats
++
++    def _getGeom(self, ln_id):
++
++        poPoints = Vect_new_line_struct()
++        if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
++            Vect_destroy_line_struct(poPoints)
++            return None
++
++        geom = self._convertGeom(poPoints)
++        Vect_destroy_line_struct(poPoints)
++        return geom
++
++    def _convertGeom(self, poPoints):
++
++        Points = poPoints.contents
++
++        pts_geom = []
++        for j in range(Points.n_points):
++            pts_geom.append((Points.x[j], Points.y[j]))
++
++        return pts_geom
++
+     def MoveSelectedLines(self, move):
+         """!Move selected features
+ 
+@@ -536,16 +662,39 @@
+         if not self._checkMap():
+             return -1
+         
++        nsel = len(self._display.selected['ids'])
++        if nsel < 1:
++            return -1   
++        
+         thresh = self._display.GetThreshold()
+         snap   = self._getSnapMode()
+         
+         poList = self._display.GetSelectedIList()
++
++        old_geoms = []
++        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()
+         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)
++
+         Vect_destroy_list(poList)
+         
++        cList = poNewIds.contents
++
++        if nlines > 0:
++            new_areas_cats = []
++            for i in range(cList.n_values):
++                new_id = cList.value[i]
++                new_areas_cats.append(self._getLineAreasCategories(new_id))
++
++        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 @@
+         if nlines > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++ 
++            self.featuresMoved.emit(move = move, 
++                                    old_geoms = old_geoms, 
++                                    old_areas_cats = old_areas_cats, 
++                                    new_areas_cats = new_areas_cats)
+         return nlines
+ 
+     def MoveSelectedVertex(self, point, move):
+@@ -571,20 +724,33 @@
+         
+         if len(self._display.selected['ids']) != 1:
+             return -1
+-        
++
++        # move only first found vertex in bbox 
++        poList = self._display.GetSelectedIList()
++
++        cList = poList.contents
++        old_geom = self._getGeom(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)
+-        
+-        # move only first found vertex in bbox 
+-        poList = self._display.GetSelectedIList()
++
++        poNewIds = Vect_new_list()
+         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(),
+                                   move[0], move[1], 0.0,
+-                                  1, self._getSnapMode())
++                                  1, self._getSnapMode(), poNewIds)
+         Vect_destroy_list(poList)
+-        
++
++        new_id = poNewIds.contents.value[0]
++        Vect_destroy_list(poNewIds)
++
++        if new_id > -1:
++            new_geom = self._getGeom(new_id)
++            new_areas_cats = self._getLineAreasCategories(new_id)
++
+         if moved > 0 and self._settings['breakLines']:
+             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+                                           None)
+@@ -592,7 +758,13 @@
+         if moved > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++
++        if new_id > -1:
++            self.vertexMoved.emit(new_geom = new_geom,  
++                                  new_areas_cats = new_areas_cats, 
++                                  old_areas_cats = old_areas_cats, 
++                                  old_geom = old_geom)
++
+         return moved
+ 
+     def AddVertex(self, coords):
+@@ -681,6 +853,9 @@
+             self._error.ReadLine(line)
+             return -1
+         
++        old_geom = self._getGeom(line)
++        old_areas_cats = self._getLineAreasCategories(line)
++
+         # build feature geometry
+         Vect_reset_line(self.poPoints)
+         for p in coords:
+@@ -703,7 +878,15 @@
+         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, 
++                                 old_areas_cats = old_areas_cats, 
++                                 new_geom = new_geom, 
++                                 new_areas_cats = new_areas_cats)
++
+         return newline
+ 
+     def FlipLine(self):
+@@ -1510,26 +1693,49 @@
+             return 0
+         
+         poList  = self._display.GetSelectedIList()
++        cList = poList.contents
++        
++        old_geom = self._getGeom(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()
++
+         if add:
+             ret = Vedit_add_vertex(self.poMapInfo, poList,
+-                                   self.poPoints, thresh)
++                                   self.poPoints, thresh, poNewIds)
+         else:
+             ret = Vedit_remove_vertex(self.poMapInfo, poList,
+-                                      self.poPoints, thresh)
++                                      self.poPoints, thresh, poNewIds)
++
++        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 not add and ret > 0 and self._settings['breakLines']:
+             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+                                           None)
+-        
++
+         if ret > 0:
+             self._addChangeset()
+-                
++
++        if new_id > -1:
++            if add:
++                self.vertexAdded.emit(old_geom = old_geom, new_geom = new_geom)
++            else:
++                self.vertexRemoved.emit(old_geom = old_geom, 
++                                        new_geom = new_geom,
++                                        old_areas_cats = old_areas_cats,
++                                        new_areas_cats = new_areas_cats)
++
+         return 1
+     
+     def GetLineCats(self, line):
+Index: gui/wxpython/vdigit/toolbars.py
+===================================================================
+--- gui/wxpython/vdigit/toolbars.py	(revision 57285)
++++ 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)
+@@ -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
+===================================================================
+--- gui/wxpython/Makefile	(revision 57285)
++++ 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)
+ 
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57285)
++++ 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 57285)
++++ 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
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
++
++        from scatt_plot.dialogs import ScattPlotMainDialog
++        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
++        
++        self.dialogs['scatt_plot'].CenterOnScreen()
++        self.dialogs['scatt_plot'].Show()
++
+     def OnVNet(self, event):
+         """!Dialog for v.net* modules 
+         """
+Index: lib/vector/vedit/move.c
+===================================================================
+--- lib/vector/vedit/move.c	(revision 57285)
++++ 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 57285)
++++ 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 */
+Index: lib/imagery/scatt_sccats.c
+===================================================================
+--- lib/imagery/scatt_sccats.c	(revision 0)
++++ lib/imagery/scatt_sccats.c	(working copy)
+@@ -0,0 +1,321 @@
++/*!
++   \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_vals, 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_vals->b_conds_arr && cats->type == 1)
++        return -1;
++
++    if(!scatt_vals->scatt_vals_arr && cats->type == 0)
++        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_vals;
++    ++scatts->n_a_scatts;
++
++    return 0;
++}
++
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_vals, 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_vals = 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_vals = 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_vals, int n_vals, int type)
++{
++    scatt_vals->n_vals = n_vals;
++
++    if(type == 0)
++    {   
++        scatt_vals->scatt_vals_arr = (unsigned int *) malloc(n_vals * sizeof(unsigned int));
++        memset(scatt_vals->scatt_vals_arr, 0, n_vals * sizeof(unsigned int));
++        scatt_vals->b_conds_arr = NULL;
++    }
++    else if(type == 1)
++    {   
++        scatt_vals->b_conds_arr = (unsigned short *) malloc(n_vals * sizeof(unsigned short));
++        memset(scatt_vals->b_conds_arr, 0, n_vals * sizeof(unsigned short));
++        scatt_vals->scatt_vals_arr = NULL;
++    }
++
++    return;
++}
++
++void I_scd_free_scatt_data(struct scdScattData * scatt_vals)
++{
++
++    free(scatt_vals->b_conds_arr);
++    free(scatt_vals->scatt_vals_arr);
++
++    scatt_vals = NULL;
++
++    return;
++}
++
++int I_scd_get_data_size(struct scdScattData * scatt_vals)
++{
++    return scatt_vals->n_vals;
++}
++
++void * I_scd_get_data_ptr(struct scdScattData * scatt_vals)
++{
++    if(!scatt_vals->b_conds_arr)
++        return scatt_vals->b_conds_arr;
++    else if(!scatt_vals->scatt_vals_arr)
++        return scatt_vals->scatt_vals_arr;
++
++    return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_vals, unsigned int val_idx, unsigned int val)
++{
++    if(val_idx < 0 && val_idx >  scatt_vals->n_vals)
++        return -1;
++
++    if(scatt_vals->b_conds_arr)
++        scatt_vals->b_conds_arr[val_idx] = val;
++    else if(scatt_vals->scatt_vals_arr)
++        scatt_vals->scatt_vals_arr[val_idx] = val;
++    else
++        return -1;
++
++    return 0;
++}
+Index: lib/imagery/scatt.c
+===================================================================
+--- lib/imagery/scatt.c	(revision 0)
++++ lib/imagery/scatt.c	(working copy)
+@@ -0,0 +1,582 @@
++/*!
++   \file lib/imagery/scatt.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>
++
++
++static const int CAT_RAST_SCATT_SEL = 2;
++static const int CAT_RAST_RAST_SEL = 1;
++static const int  CAT_RAST_NULL = 0;
++
++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);
++}
++
++int I_create_cat_rast(struct Cell_head * cat_rast_region,  const char * cat_rast)
++{
++    FILE * f_cat_rast;
++    char cat_rast_header[1024];//TODO magic number 
++    int i_row, i_col;
++    int head_nchars;
++
++    unsigned char * row_data;
++
++    f_cat_rast = fopen(cat_rast, "wb");
++    if(!f_cat_rast)
++        return -1;
++
++    head_nchars = get_cat_rast_header(cat_rast_region, cat_rast_header);
++
++    fwrite(cat_rast_header, sizeof(char), head_nchars/sizeof(char), f_cat_rast);
++    if (ferror(f_cat_rast)){
++        fclose(f_cat_rast);
++        return -1;
++    }
++
++    row_data = (unsigned char *) G_malloc(cat_rast_region->cols * sizeof(unsigned char));
++    for(i_col = 0; i_col < cat_rast_region->cols; i_col++)
++        row_data[i_col] = 0 & 255;
++
++    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);
++            G_debug(3, "Unable to write into file.");
++            return -1;
++        }
++    }
++
++    fclose(f_cat_rast);
++    return 0;
++}
++
++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, 
++               intersec->east, intersec->west, intersec->ns_res, intersec->ew_res);
++}
++
++static int regions_intersecion(struct Cell_head * A, struct Cell_head * B, struct Cell_head * intersec)
++{
++
++    if(B->north < A->south) return -1;
++    else if(B->north > A->north) intersec->north = A->north;
++    else intersec->north = B->north;
++
++    if(B->south > A->north) return -1;
++    else if(B->south < A->south) intersec->south = A->south;
++    else intersec->south = B->south;
++
++    if(B->east < A->west) return -1;
++    else if(B->east > A->east) intersec->east = A->east;
++    else intersec->east = B->east;
++
++    if(B->west > A->east) return -1;
++    else if(B->west < A->west) intersec->west = A->west;
++    else intersec->west = B->west;
++
++    if(intersec->north == intersec->south) return -1;
++
++    if(intersec->east == intersec->west) return -1;
++
++    return 0;
++
++}
++
++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)
++        return -1;
++
++    if(A->ew_res != B->ew_res)
++        return -1;
++
++    ns_res = A->ns_res;
++    ew_res = A->ew_res;
++
++    if(regions_intersecion(A, B, &intersec) == -1)
++        return -1;
++
++    A_bounds->north = ceil((A->north - intersec.north - ns_res * 0.5) / ns_res);
++    A_bounds->south = ceil((A->north - intersec.south - ns_res * 0.5) / ns_res);
++
++    A_bounds->east = ceil((intersec.east - A->west - ew_res * 0.5) / ew_res);
++    A_bounds->west = ceil((intersec.west - A->west - ew_res * 0.5) / ew_res);
++
++    B_bounds->north = ceil((B->north - intersec.north - ns_res * 0.5) / ns_res);
++    B_bounds->south = ceil((B->north - intersec.south - ns_res * 0.5) / ns_res);
++
++    B_bounds->east = ceil((intersec.east - B->west - ew_res * 0.5) / ew_res);
++    B_bounds->west = ceil((intersec.west - B->west - ew_res * 0.5) / ew_res);
++
++    return 0;
++}
++
++
++int I_insert_patch_to_cat_rast(const char * patch_rast, struct Cell_head * cat_rast_region,  const char * cat_rast)
++{
++
++    FILE * f_cat_rast;
++    struct Cell_head patch_region, patch_bounds, cat_rast_bounds;
++    char cat_rast_header[1024];//TODO magic number 
++    int i_row, i_col, ncols, nrows, cat_rast_col, patch_col, val;
++    int head_nchars;
++    int fd_patch_rast, init_shift, step_shift;
++    unsigned char * patch_data;
++
++    char * null_chunk;
++
++    //TODO G_free mapset (aslo in compute  scatts)
++    const char *mapset;
++
++    struct Cell_head patch_lines, cat_rast_lines;
++
++    unsigned char * row_data;
++
++    f_cat_rast = fopen(cat_rast, "rb+");
++    if(!f_cat_rast)
++        return -10;
++
++
++    /* 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;
++    }
++
++    Rast_get_cellhd(patch_rast, mapset, &patch_region);
++    Rast_set_window(&patch_region);
++            
++    if ((fd_patch_rast = Rast_open_old(patch_rast, mapset)) < 0) {
++        fclose(f_cat_rast);
++        return -3;
++    }
++
++    null_chunk =  Rast_allocate_null_buf();
++
++    if(get_rows_and_cols_bounds(cat_rast_region, &patch_region, &cat_rast_bounds, &patch_bounds) == -1) return -1;
++
++    ncols = cat_rast_bounds.east - cat_rast_bounds.west;
++    nrows = cat_rast_bounds.south - cat_rast_bounds.north;
++
++    patch_data = (unsigned char *) G_malloc(ncols * sizeof(unsigned char));
++
++    init_shift = head_nchars + cat_rast_region->cols * cat_rast_bounds.north + cat_rast_bounds.west;
++
++    if(fseek(f_cat_rast, init_shift, SEEK_SET) != 0) {
++        G_message("seek failed");
++        return -4;
++    }
++
++    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);
++
++        for(i_col = 0; i_col < ncols; i_col++) {
++            patch_col = patch_bounds.west + i_col;
++
++            if(null_chunk[patch_col] != 1) 
++                patch_data[i_col] = 1 & 255;
++            else {
++                patch_data[i_col] = 0 & 255;
++            }
++        }
++
++        fwrite(patch_data, sizeof(unsigned char), (ncols)/sizeof(unsigned char), f_cat_rast);
++        if (ferror(f_cat_rast))
++        {
++            G_free(null_chunk);
++            fclose(f_cat_rast);
++            return -5;
++        }
++        if(fseek(f_cat_rast, step_shift, SEEK_CUR) != 0) {
++            G_message("seek failed");
++            return -6;
++        }
++    }
++
++    Rast_close(fd_patch_rast);
++    G_free(null_chunk);
++    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)
++{
++    int band_axis_1, band_axis_2, i_scatt, array_idx, cat_idx, i_chunks_pix;
++    int r_bits = 256;
++
++    CELL * band_1_chunks;
++    CELL * band_2_chunks;
++    char * band_1_null_chunks,* band_2_null_chunks;
++
++    int * scatts_bands = scatts->scatts_bands;
++    for(i_scatt = 0; i_scatt < scatts->n_a_scatts; i_scatt++)
++    {   
++        band_1_chunks = chunks[scatts_bands[i_scatt * 2]];
++        band_2_chunks = chunks[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]];
++
++        for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++        {
++            if(!belongs_pix[i_chunks_pix] || 
++                band_1_null_chunks[i_chunks_pix] == 1 || 
++                band_2_null_chunks[i_chunks_pix] == 1)                
++                continue;
++
++            array_idx = band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits;
++
++            ++scatts->scatts_arr[i_scatt]->scatt_vals_arr[array_idx];
++        }
++    }
++}
++
++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)
++{
++
++    int i_chunks_pix, i_cat, i_scatt, n_a_scatts, i_cond;
++    int cat_id, scatt_plts_cat_idx, array_idx;
++    char * band_1_null_chunks,* band_2_null_chunks;
++    
++    int r_bits = 256;
++
++    struct scScatts * scatts_conds;
++    struct scScatts * scatt_plts_scatts;
++    struct scdScattData * conds;
++
++    int * scatts_bands;
++    struct scdScattData ** scatts_arr;
++
++    CELL * band_1_chunks;
++    CELL * band_2_chunks;
++    unsigned int * 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));
++
++    for(i_cat = 0; i_cat < scatt_conds->n_a_cats; i_cat++)
++    {
++        scatts_conds = scatt_conds->cats_arr[i_cat];
++
++        cat_id = scatt_conds->cats_ids[i_cat];
++
++        scatt_plts_cat_idx = scatt_plts->cats_idxs[cat_id];
++        if(scatt_plts_cat_idx < 0)
++            continue;
++
++        scatt_plts_scatts = scatt_plts->cats_arr[scatt_plts_cat_idx];
++
++        G_zero(belongs_pix, chunk_size * sizeof(unsigned short));
++
++        if(!scatts_conds->n_a_scatts && !f_cats_rasts_in[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;
++            }
++        }
++        else
++        {
++            scatts_bands = scatts_conds->scatts_bands;
++
++            if(f_cats_rasts_in[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]))
++                {
++                    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++)
++                {
++                    if(rast_pixs[i_chunks_pix] != 0 & 255)
++                        belongs_pix[i_chunks_pix] = 1;
++                }
++
++            // test every defined conditions in scatter plots
++            for(i_scatt = 0; i_scatt < scatts_conds->n_a_scatts; i_scatt++)
++            {   
++                band_1_chunks =  chunks[scatts_bands[i_scatt * 2]];
++                band_2_chunks =  chunks[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]];
++
++                i_scatt_conds = scatts_conds->scatts_arr[i_scatt]->b_conds_arr;
++
++                for(i_chunks_pix = 0; i_chunks_pix < chunk_size; i_chunks_pix++)
++                {
++                    if(belongs_pix[i_chunks_pix] || 
++                       band_1_null_chunks[i_chunks_pix] == 1 || 
++                       band_2_null_chunks[i_chunks_pix] == 1)
++                        continue;
++
++                    if(i_scatt_conds[band_1_chunks[i_chunks_pix] + band_2_chunks[i_chunks_pix] * r_bits])
++                        belongs_pix[i_chunks_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;
++
++            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;
++            }
++        }
++
++        update_cat_scatt_plt(chunks, null_chunks, chunk_size, belongs_pix, scatt_plts_scatts);
++    }
++
++    G_free(rast_pixs);
++    G_free(belongs_pix);
++
++    return 0;
++}
++
++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
++    int i_cat, i_scatt, cat_id;
++
++    for(i_cat = 0;  i_cat < cats->n_a_cats; i_cat++)
++    {   
++        for(i_scatt = 0;  i_scatt < cats->cats_arr[i_cat]->n_a_scatts; i_scatt++)
++        {   
++            G_debug(3, "Active scatt %d in catt %d", i_scatt, i_cat);
++
++            b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2]] = 1;
++            b_needed_bands[cats->cats_arr[i_cat]->scatts_bands[i_scatt * 2 + 1]] = 1;
++        }
++    }
++    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)
++{
++    int i, band_id;
++
++    for(i = 0; i < (* n_a_bands); i++)
++    {   
++        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]);
++        }
++    }
++
++    if(f_cats_rasts_in)
++        for(i = 0; i < n_a_cats; i++)
++            if(f_cats_rasts_in[i])
++                fclose(f_cats_rasts_in[i]);
++
++    if(f_cats_rasts_out)
++        for(i = 0; i < n_a_cats; i++)
++            if(f_cats_rasts_out[i])
++                fclose(f_cats_rasts_out[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)
++{
++    int i_cat, id_cat;
++
++    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
++    {
++        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;
++        }
++        else
++            f_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)
++{
++    int i_cat, id_cat, head_nchars;
++    char cat_rast_header[1024];//TODO magic number 
++
++    head_nchars = get_cat_rast_header(region, cat_rast_header);
++
++    for(i_cat = 0; i_cat < n_a_cats; i_cat++)
++    {
++        if(!f_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;
++    }
++
++    return head_nchars;
++
++}
++
++//TODO change name: I_UpdateScattData???
++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 ||
++        n_bands != scatt_conds->n_bands)
++        return -1;
++
++    const char *mapset;
++
++    FILE * f_cats_rasts_out[scatt_conds->n_a_cats];
++    FILE * f_cats_rasts_in[scatt_conds->n_a_cats];
++
++    CELL * chunks[n_bands];
++    char * null_chunks[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;
++    int fd_bands[n_bands];
++    for(i_band = 0; i_band < n_bands; i_band++)
++        fd_bands[i_band] = -1;
++    
++    int bands_ids[n_bands];
++    for(i_band = 0; i_band < n_bands; i_band++)
++        bands_ids[i_band] = -1;
++
++    int b_needed_bands[n_bands];  
++    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]);
++
++    Rast_set_window(region);
++
++    n_a_bands = 0;/*TODO realy needed?*/
++    for(id_band = 0; id_band < n_bands; id_band++)
++    {
++        if(b_needed_bands[id_band])
++        {
++            G_debug(3, "Opening raster no. %d with name: %s", id_band, bands[id_band]);
++
++            /* 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, 
++                                   &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
++                return -1;
++            }
++            
++            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, 
++                                   &bands_ids[0], NULL, NULL, scatt_conds->n_a_cats);
++                return -1;
++            }
++
++            //TODO check data type, minimum and maximum value
++            data_type = Rast_get_map_type(fd_bands[n_a_bands]);
++            //if(data_type != CELL)
++            //    return -1;
++
++            //What happens if it is not CELL tyoe
++            chunks[id_band] =  Rast_allocate_c_buf();
++            null_chunks[id_band] =  Rast_allocate_null_buf();
++
++            bands_ids[n_a_bands] = id_band;
++
++            ++n_a_bands;
++        }
++    }
++
++    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;
++    }
++
++    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;
++    }
++
++    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;
++    }
++
++    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);
++
++    i_chunk = 0;
++
++    nrows = Rast_window_rows();
++    chunk_size = Rast_window_cols();
++
++    for (i_row = 0; i_row < nrows; i_row++)
++    {
++        for(i_band = 0; i_band < n_a_bands; i_band++)
++        {   
++            band_id = bands_ids[i_band];
++            G_debug(3, "Reading data for band %d", band_id);
++            Rast_get_c_row(fd_bands[i_band], chunks[band_id], i_row);
++            Rast_get_null_value_row (fd_bands[i_band], null_chunks[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) 
++        {
++            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], &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 0;    
++}
+\ No newline at end of file



More information about the grass-commit mailing list