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

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Aug 28 09:01:32 PDT 2013


Author: turek
Date: 2013-08-28 09:01:30 -0700 (Wed, 28 Aug 2013)
New Revision: 57530

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
scatter plot: plots rendering memory and speed  optimization

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-08-28 15:01:45 UTC (rev 57529)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-08-28 16:01:30 UTC (rev 57530)
@@ -1,47 +1,6 @@
-Index: include/defs/vedit.h
-===================================================================
---- include/defs/vedit.h	(revision 57506)
-+++ include/defs/vedit.h	(working copy)
-@@ -33,6 +33,8 @@
- int Vedit_merge_lines(struct Map_info *, struct ilist *);
- 
- /* move.c */
-+int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
-+		     		 struct ilist *, double, double, double, int, double);
- int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
- 		     struct ilist *, double, double, double, int, double);
- 
-Index: include/defs/imagery.h
-===================================================================
---- include/defs/imagery.h	(revision 57506)
-+++ include/defs/imagery.h	(working copy)
-@@ -110,6 +110,23 @@
- FILE *I_fopen_subgroup_ref_new(const char *, const char *);
- FILE *I_fopen_subgroup_ref_old(const char *, const char *);
- 
-+/* scatt_plt.c */
-+void I_sc_init_cats(struct scCats *, int, int);
-+void I_sc_free_cats(struct scCats *);
-+int I_sc_add_cat(struct scCats *);
-+int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
-+
-+void I_scd_init_scatt_data(struct scdScattData *, int, int, void *);
-+
-+int I_compute_scatts(struct Cell_head *, struct scCats *, const char **, 
-+	                 const char **, int, struct scCats *, const char **);
-+
-+int I_create_cat_rast(struct Cell_head *, const char *);
-+int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
-+
-+int I_id_scatt_to_bands(const int, const int, int *, int *);
-+int I_bands_to_id_scatt(const int, const int, const int, int *);
-+
- /* sig.c */
- int I_init_signatures(struct Signature *, int);
- int I_new_signature(struct Signature *);
 Index: include/imagery.h
 ===================================================================
---- include/imagery.h	(revision 57506)
+--- include/imagery.h	(revision 57529)
 +++ include/imagery.h	(working copy)
 @@ -135,6 +135,56 @@
      
@@ -100,6 +59,717 @@
  #define SIGNATURE_TYPE_MIXED 1
  
  #define GROUPFILE "CURGROUP"
+Index: include/defs/vedit.h
+===================================================================
+--- include/defs/vedit.h	(revision 57529)
++++ include/defs/vedit.h	(working copy)
+@@ -33,6 +33,8 @@
+ int Vedit_merge_lines(struct Map_info *, struct ilist *);
+ 
+ /* move.c */
++int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
++		     		 struct ilist *, double, double, double, int, double);
+ int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
+ 		     struct ilist *, double, double, double, int, double);
+ 
+Index: include/defs/imagery.h
+===================================================================
+--- include/defs/imagery.h	(revision 57529)
++++ include/defs/imagery.h	(working copy)
+@@ -110,6 +110,23 @@
+ FILE *I_fopen_subgroup_ref_new(const char *, const char *);
+ FILE *I_fopen_subgroup_ref_old(const char *, const char *);
+ 
++/* scatt_plt.c */
++void I_sc_init_cats(struct scCats *, int, int);
++void I_sc_free_cats(struct scCats *);
++int I_sc_add_cat(struct scCats *);
++int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
++
++void I_scd_init_scatt_data(struct scdScattData *, int, int, void *);
++
++int I_compute_scatts(struct Cell_head *, struct scCats *, const char **, 
++	                 const char **, int, struct scCats *, const char **);
++
++int I_create_cat_rast(struct Cell_head *, const char *);
++int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
++
++int I_id_scatt_to_bands(const int, const int, int *, int *);
++int I_bands_to_id_scatt(const int, const int, const int, int *);
++
+ /* sig.c */
+ int I_init_signatures(struct Signature *, int);
+ int I_new_signature(struct Signature *);
+Index: 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,166 @@
++"""!
++ 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)
++"""
++
++import sys
++from multiprocessing import Process, Queue
++
++from ctypes import *
++try:
++    from grass.lib.imagery import *
++    from grass.lib.gis import Cell_head, G_get_window
++except ImportError, e:
++    sys.stderr.write(_("Loading imagery lib failed"))
++
++from core.gcmd import GException
++
++
++def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_conds, cats_rasts):
++    q = Queue()
++    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
++                                                    n_bands, scatts, cats_rasts_conds, cats_rasts, q))
++    p.start()
++    ret = q.get()
++    p.join()
++
++    return ret[0], ret[1]
++
++def UpdateCatRast(patch_rast, region, cat_rast):
++    q = Queue()
++    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
++    p.start()
++    ret = q.get()
++    p.join()
++
++    return ret
++
++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_conds, cats_rasts, output_queue):
++
++    #TODO names for types not 0 and 1?
++    sccats_c, cats_rasts_c, refs = _getComputationStruct(scatts, cats_rasts, 0, n_bands)
++    scatt_conds_c, cats_rasts_conds_c, refs2 = _getComputationStruct(scatt_conds, cats_rasts_conds, 1, n_bands)
++
++    char_bands = _stringListToCharArr(bands)
++   
++    cell_head = _regionToCellHead(region)
++
++    ret = I_compute_scatts(pointer(cell_head),
++                           pointer(scatt_conds_c),
++                           pointer(cats_rasts_conds_c),
++                           pointer(char_bands),
++                           n_bands,
++                           pointer(sccats_c),
++                           pointer(cats_rasts_c))
++
++    I_sc_free_cats(pointer(sccats_c))
++    I_sc_free_cats(pointer(scatt_conds_c))
++
++    output_queue.put((ret, scatts))
++
++def _getBandcRange( band_info):
++    band_c_range = struct_Range()
++
++    band_c_range.max = band_info['max']
++    band_c_range.min = band_info['min']
++
++    return band_c_range
++
++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_rasts, cats_type, n_bands):
++
++    sccats = struct_scCats()
++    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
++
++    refs = []        
++    cats_rasts_core = []
++    
++    for cat_id, scatt_ids in cats.iteritems():
++        cat_c_id = I_sc_add_cat(pointer(sccats))
++        cats_rasts_core.append(cats_rasts[cat_id])
++
++        for scatt_id, dt in scatt_ids.iteritems():
++            # if key is missing condition is always True (full scatter plor is computed)
++                vals = dt['np_vals']
++
++                scatt_vals = scdScattData()
++
++                c_void_p = ctypes.POINTER(ctypes.c_void_p)
++
++                if cats_type == SC_SCATT_DATA:
++                    vals[:] = 0
++                elif cats_type == SC_SCATT_CONDITIONS:
++                    pass
++                else:
++                    return None
++                data_p = vals.ctypes.data_as(c_void_p)
++                I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p)
++
++                refs.append(scatt_vals)
++
++                I_sc_insert_scatt_data(pointer(sccats),  
++                                       pointer(scatt_vals),
++                                       cat_c_id, scatt_id)
++
++    cats_rasts_c = _stringListToCharArr(cats_rasts_core)
++
++    return sccats, cats_rasts_c, refs
++
++def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
++    cell_head = _regionToCellHead(region)
++    
++    
++    ret = I_insert_patch_to_cat_rast(patch_rast, 
++                                     pointer(cell_head), 
++                                     cat_rast)
++
++    output_queue.put(ret)
++
++
+Index: gui/wxpython/scatt_plot/frame.py
+===================================================================
+--- gui/wxpython/scatt_plot/frame.py	(revision 0)
++++ gui/wxpython/scatt_plot/frame.py	(working copy)
+@@ -0,0 +1,494 @@
++"""!
++ at package scatt_plot.dialogs
++
++ at brief GUI.
++
++Classes:
++
++(C) 2013 by the GRASS Development Team
++
++This program is free software under the GNU General Public License
++(>=v2). Read the file COPYING that comes with GRASS for details.
++
++ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
++"""
++import os
++import sys
++
++import wx
++import wx.lib.scrolledpanel as scrolled
++import wx.lib.mixins.listctrl as listmix
++import wx.lib.flatnotebook  as FN
++import wx.aui
++
++from core import globalvar
++from core.gcmd import GException, GError, RunCommand
++
++from gui_core.gselect import Select
++
++from scatt_plot.controllers import ScattsManager
++from scatt_plot.toolbars import MainToolbar, EditingToolbar
++from scatt_plot.scatt_core import idScattToidBands
++from scatt_plot.plots import ScatterPlotWidget
++
++try:
++    from agw import aui
++except ImportError:
++    import wx.lib.agw.aui as aui
++
++class IClassScatterPlotsPanel(wx.Panel):
++    def __init__(self, parent, giface, iclass_mapwin = None,
++                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++
++        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
++        #                           style = wx.SP_LIVE_UPDATE)
++        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++
++        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
++        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
++
++        # toobars
++        self.toolbars = {}
++        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        
++        self._createCategoryPanel(self)
++
++        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
++        mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
++        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
++        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
++
++        self.catsPanel.Hide()
++        self.toolbars['editingToolbar'].Hide()
++
++        self.SetSizer(mainsizer)
++        
++        #self.SetSashGravity(0.5)
++        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
++        self.Layout()
++
++    def NewScatterPlot(self, scatt_id):
++        return self.plot_panel.NewScatterPlot(scatt_id)
++
++    def ShowPlotEditingToolbar(self, show):
++        self.toolbars["editingToolbar"].Show(show)
++        self.Layout()
++
++    def ShowCategoryPanel(self, show):
++        self.catsPanel.Show(show)
++        
++        #if show:
++        #    self.SetSashSize(5) 
++        #else:
++        #    self.SetSashSize(0)
++        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
++        self.Layout()
++
++    def _createCategoryPanel(self, parent):
++        self.catsPanel = wx.Panel(parent = parent)
++        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
++                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
++
++        self.catsPanel.SetMaxSize((-1, 150))
++
++        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
++                             label = ' %s ' % _("Classes manager for scatter plots"))
++        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
++
++        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++        self.catsPanel.SetSizer(catsSizer)
++
++
++class IClassPlotPanel(scrolled.ScrolledPanel):
++    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
++    
++        scrolled.ScrolledPanel.__init__(self, parent)
++        self.SetupScrolling(scroll_x = False, scroll_y = True, scrollToTop = False)
++
++        self.scatt_mgr = scatt_mgr
++
++        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
++
++        #self._createCategoryPanel()
++        # Fancy gui
++        self._mgr = aui.AuiManager(self.mainPanel)
++        #self._mgr.SetManagedWindow(self)
++
++        self._mgr.Update()
++
++        self._doLayout()
++        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
++        self.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged)
++
++        self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed)
++
++        dlgSize = (-1, 400)
++        #self.SetBestSize(dlgSize)
++        #self.SetInitialSize(dlgSize)
++        self.SetAutoLayout(1)
++        #fix goutput's pane size (required for Mac OSX)
++        #if self.gwindow:         
++        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
++        self.ignore_scroll = 0
++        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
++
++    def OnMouseWheel(self, event):
++        #TODO very ugly find some better solution        
++        self.ignore_scroll = 3
++        event.Skip()
++
++    def ScrollChildIntoView(self, child):
++        #For aui manager it does not work and returns position always to the top -> deactivated.
++        pass
++
++    def OnPlotPaneClosed(self, event):
++        if isinstance(event.pane.window, ScatterPlotWidget):
++            event.pane.window.CleanUp()
++
++    def OnScrollChanged(self, event):
++        print "changed"
++        wx.CallAfter(self.Layout)
++
++
++    def OnScroll(self, event):
++        if self.ignore_scroll > 0:
++            self.ignore_scroll -= 1
++        else:
++            event.Skip()
++
++        #wx.CallAfter(self._mgr.Update)
++        #wx.CallAfter(self.Layout)
++
++    def _doLayout(self):
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
++        self.SetSizer(mainsizer)
++
++        self.Layout()
++        self.SetupScrolling()
++
++    def OnCloseDialog(self, event):
++        """!Close dialog"""
++        self.scatt_mgr.CleanUp()
++        self.Destroy()
++
++    def OnSettings(self, event):
++        pass
++
++    def NewScatterPlot(self, scatt_id):
++        #TODO needs to be resolved (should be in this class)
++
++        scatt = ScatterPlotWidget(parent = self.mainPanel, 
++                                  scatt_mgr = self.scatt_mgr, 
++                                  scatt_id = scatt_id)
++
++        bands = self.scatt_mgr.GetBands()
++        #TODO too low level
++        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
++
++        self._mgr.AddPane(scatt,
++                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
++                           Name("scatter plot %d" % scatt_id).MinSize((-1, 300)).Caption(("%s x: %s y: %s") % (_("scatter plot"), bands[b1_id], bands[b2_id])).
++                           Center().Position(1).MaximizeButton(True).
++                           MinimizeButton(True).CaptionVisible(True).
++                           CloseButton(True).Layer(0))
++        
++
++        self._mgr.Update()
++  
++        self.SetVirtualSize(self.GetBestVirtualSize())
++        self.Layout()
++
++        return scatt
++
++    def GetScattMgr(self):
++        return  self.scatt_mgr
++
++class CategoryListCtrl(wx.ListCtrl,
++                       listmix.ListCtrlAutoWidthMixin,
++                       listmix.TextEditMixin):
++
++    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++
++        wx.ListCtrl.__init__(self, parent, id,
++                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++        self.columns = ((_('Class name'), 'name'),
++                        (_('Color'), 'color'))
++        self.Populate(columns = self.columns)
++        
++        self.cats_mgr = cats_mgr
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++
++        self.rightClickedItemIdx = wx.NOT_FOUND
++        
++        listmix.ListCtrlAutoWidthMixin.__init__(self)
++
++        listmix.TextEditMixin.__init__(self)
++        
++        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
++        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
++             
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++        self.cats_mgr.deletedCategory.connect(self.Update)
++        self.cats_mgr.addedCategory.connect(self.Update)
++
++    def Update(self, **kwargs):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def InitCoreCats(self):
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
++
++    def SetVirtualData(self, row, column, text):
++        attr = self.columns[column][1]
++        if attr == 'name':
++            try:
++                text.encode('ascii')
++            except UnicodeEncodeError:
++                GMessage(parent = self, message = _("Please use only ASCII characters."))
++                return
++
++        cat_id = self.cats_mgr.GetCategories()[row]
++
++        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
++        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
++        self.cats_mgr.setCategoryAttrs.connect(self.Update)
++        
++        self.Select(row)
++        
++    def Populate(self, columns):
++        for i, col in enumerate(columns):
++            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
++
++        self.SetColumnWidth(0, 100)
++        self.SetColumnWidth(1, 100)
++        
++    def AddCategory(self):
++
++        self.cats_mgr.addedCategory.disconnect(self.Update)
++        cat_id = self.cats_mgr.AddCategory()
++        self.cats_mgr.addedCategory.connect(self.Update)
++
++        if cat_id < 0:
++            GError(_("Maximum limit of categories number was reached."))
++            return
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++                        
++    def DeleteCategory(self):
++        indexList = sorted(self.GetSelectedIndices(), reverse = True)
++        cats = []
++        for i in indexList:
++            # remove temporary raster
++            cat_id = self.cats_mgr.GetCategories()[i]
++            
++            cats.append(cat_id)
++
++            self.cats_mgr.deletedCategory.disconnect(self.Update)
++            self.cats_mgr.DeleteCategory(cat_id)
++            self.cats_mgr.deletedCategory.connect(self.Update)
++            
++        self.SetItemCount(len(self.cats_mgr.GetCategories()))
++        
++    def OnSel(self, event): 
++        event.Skip()
++
++    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
++        indices = []
++        lastFound = -1
++        while True:
++            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
++            if index == -1:
++                break
++            else:
++                lastFound = index
++                indices.append(index)
++        return indices        
++
++    def OnEdit(self, event):
++        currentItem = event.m_itemIndex
++        currentCol = event.m_col
++
++        if currentCol == 1:
++            dlg = wx.ColourDialog(self)
++            dlg.GetColourData().SetChooseFull(True)
++
++            if dlg.ShowModal() == wx.ID_OK:
++                color = dlg.GetColourData().GetColour().Get()
++                color = ':'.join(map(str, color))
++                self.SetVirtualData(currentItem, currentCol, color)
++            dlg.Destroy()
++            wx.CallAfter(self.SetFocus)
++        
++        event.Skip()
++        
++        
++    def DeselectAll(self):
++        """!Deselect all items"""
++        indexList = self.GetSelectedIndices()
++        for i in indexList:
++            self.Select(i, on = 0)
++         
++        # no highlight
++        self.OnCategorySelected(None)
++        
++    def OnGetItemText(self, item, col):
++        attr = self.columns[col][1]
++        cat_id = self.cats_mgr.GetCategories()[item]
++
++        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
++
++    def OnGetItemImage(self, item):
++        return -1
++
++    def OnGetItemAttr(self, item):
++        return None
++
++    def OnClassRightUp(self, event):
++        """!Show context menu on right click"""
++        item, flags = self.HitTest((event.GetX(), event.GetY()))
++        if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
++            self.rightClickedItemIdx = item
++           
++        self.popupZoomtoAreas = wx.NewId()
++        self.Bind(wx.EVT_MENU, self.OnZoomToAreasByCat, id = self.popupZoomtoAreas)
++
++        # generate popup-menu
++        menu = wx.Menu()
++        menu.Append(self.popupZoomtoAreas, _("Zoom to training areas of selected class"))
++        
++        self.PopupMenu(menu)
++        menu.Destroy()
++    
++    def OnZoomToAreasByCat(self, event):
++        """!Zoom to areas of given category"""
++        cat = self.stats_data.GetCategories()[self.rightClickedItemIdx]
++        self.mapWindow.ZoomToAreasByCat(cat)
++
++class AddScattPlotDialog(wx.Dialog):
++
++    def __init__(self, parent, bands, id  = wx.ID_ANY):
++        
++        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
++
++        self.bands = bands
++
++        self.scatt_id = None
++
++        self._createWidgets()
++
++    def _createWidgets(self):
++
++        self.labels = {}
++        self.params = {}
++
++        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
++
++        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
++
++        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
++                                     choices = self.bands,
++                                     style = wx.CB_READONLY, size = (350, 30))
++
++        # buttons
++        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
++        
++        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
++
++        self._layout()
++
++    def _layout(self):
++
++        border = wx.BoxSizer(wx.VERTICAL) 
++        dialogSizer = wx.BoxSizer(wx.VERTICAL)
++
++        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
++                                                    sel = self.band_1_ch))
++
++        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
++                                                    sel = self.band_2_ch))
++
++        # buttons
++        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
++
++        self.btnsizer.Add(item = self.btn_close, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++        
++        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
++                          flag = wx.ALL | wx.ALIGN_CENTER,
++                          border = 10)
++
++        dialogSizer.Add(item = self.btnsizer, proportion = 0,
++                        flag = wx.ALIGN_CENTER)
++
++        border.Add(item = dialogSizer, proportion = 0,
++                   flag = wx.ALL, border = 5)
++
++        self.SetSizer(border)
++        self.Layout()
++        self.Fit()
++
++        # bindings
++        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
++        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
++
++    def _addSelectSizer(self, title, sel): 
++        """!Helper layout function.
++        """
++        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
++
++        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
++        selTitleSizer.Add(item = title, proportion = 1,
++                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
++
++        selSizer.Add(item = selTitleSizer, proportion = 0,
++                     flag = wx.EXPAND)
++
++        selSizer.Add(item = sel, proportion = 1,
++                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
++                     border = 5)
++
++        return selSizer
++
++    def OnClose(self, event):
++        """!Close dialog
++        """
++        if not self.IsModal():
++            self.Destroy()
++        event.Skip()
++
++    def OnOk(self, event):
++        """!
++        """
++        band_1 = self.band_1_ch.GetSelection()
++        band_2 = self.band_2_ch.GetSelection()
++
++
++        if band_1 == band_2:
++            GError(_("Selected bands must be different."))
++            return
++        
++        #TODO axes selection
++        if band_1 > band_2:
++            tmp_band = band_2
++            band_2 = band_1
++            band_1 = band_2
++
++        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
++
++        event.Skip()
++
++    def GetScattId(self):
++        return self.scatt_id
 Index: gui/wxpython/scatt_plot/__init__.py
 ===================================================================
 --- gui/wxpython/scatt_plot/__init__.py	(revision 0)
@@ -120,7 +790,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/plots.py	(revision 0)
 +++ gui/wxpython/scatt_plot/plots.py	(working copy)
-@@ -0,0 +1,502 @@
+@@ -0,0 +1,666 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -140,6 +810,8 @@
 +import random
 +from copy import deepcopy
 +
++import scipy.misc as misc
++
 +try:
 +    haveMatPlot = True
 +    import matplotlib
@@ -152,10 +824,17 @@
 +    from matplotlib.artist import Artist
 +    from matplotlib.mlab import dist_point_to_segment
 +    from matplotlib.patches import Polygon, Ellipse
++    import matplotlib.image as mi
++    import matplotlib.colors as mcolors
++    import matplotlib.cbook as cbook
 +except ImportError:
 +    haveMatPlot = False
 +from grass.pydispatch.signal import Signal
 +
++
++#class PlotImages()?
++
++
 +class ScatterPlotWidget(wx.Panel):
 +    def __init__(self, parent, scatt_id, scatt_mgr,
 +                 id = wx.ID_ANY):
@@ -210,7 +889,6 @@
 +
 +    def SetMode(self, mode):
 +        self._deactivateMode()
-+
 +        if mode == 'zoom':
 +            self.ciddscroll = self.canvas.mpl_connect('scroll_event', self.zoom)
 +        elif mode == 'pan':
@@ -224,6 +902,7 @@
 +
 +    def _deactivateMode(self):
 +
++        #TODO do own pan
 +        if self.toolbar._active == "PAN":
 +            self.toolbar.pan()
 +
@@ -232,13 +911,6 @@
 +
 +        self._stopCategoryEdit()
 +
-+    #def _startCategoryEdit(self):
-+    #    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'
@@ -296,6 +968,9 @@
 +        self.axes.clear()
 +
 +        callafter_list = []
++
++        init = True
++
 +        for cat_id, scatt in scatts.iteritems():
 +            b1_i = scatt['bands_info']['b1']
 +            b2_i = scatt['bands_info']['b2']
@@ -319,20 +994,36 @@
 +
 +            masked_cat = np.ma.masked_less_equal(scatt['np_vals'], 0)
 +
-+            #self.axes.set_xlim((0, 270))
-+            #self.axes.set_ylim((0, 270))
-+            #np.savetxt("/home/ostepok/Desktop/data.txt", scatt['np_vals'], fmt = '%d') 
-+        
++            vmax = np.amax(masked_cat)
++            masked_cat = masked_cat/ float(vmax)
 +
-+            #TODO needs optimization
-+            img = self.axes.imshow(masked_cat, cmap = deepcopy(cmap),
-+                                               origin = 'lower',
-+                                               extent = self.full_extend, 
-+                                               interpolation='nearest',
-+                                               aspect = "auto")
++            colored_cat = np.uint8(cmap(masked_cat) * 255)
++            
++            if init:
++                merged_img = colored_cat
++                init = False
++            else:
++                for i in range(4):
++                    merged_img[...,i] = np.choose(masked_cat.mask, (colored_cat[...,i], merged_img[...,i]))
 +
-+            callafter_list.append([self.axes.draw_artist, [img]])
++                del colored_cat
++            del masked_cat
 +
++        img = imshow(self.axes, merged_img,
++                     origin = 'lower',
++                     extent = self.full_extend, 
++                     interpolation='nearest',
++                     aspect = "auto")
++
++        #TODO needs optimization
++        #img = self.axes.imshow(merged_img,
++        #                       origin = 'lower',
++        #                       extent = self.full_extend, 
++        #                       interpolation='nearest',
++        #                       aspect = "auto")
++
++        callafter_list.append([self.axes.draw_artist, [img]])
++
 +        #self.fig.savefig("/home/ostepok/Desktop/data.png")
 +
 +        for cat_id, e in ellipses.iteritems():
@@ -544,6 +1235,7 @@
 +        if len(self.pol.xy) <= 2:
 +            self.empty_pol = True
 +            self.Show(False)
++            return
 +
 +        coords = []
 +        for i,tup in enumerate(self.pol.xy): 
@@ -607,7 +1299,7 @@
 +        if self.moving_ver_idx is None: return
 +        if event.inaxes is None: return
 +        if event.button != 1: return
-+        print "moving %d" % self.it
++
 +        self.it += 1
 +
 +        x,y = event.xdata, event.ydata
@@ -623,6 +1315,149 @@
 +        self.canvas.restore_region(self.background)
 +
 +        self.Redraw()
++
++class ModestImage(mi.AxesImage):
++    """
++    Computationally modest image class.
++
++    ModestImage is an extension of the Matplotlib AxesImage class
++    better suited for the interactive display of larger images. Before
++    drawing, ModestImage resamples the data array based on the screen
++    resolution and view window. This has very little affect on the
++    appearance of the image, but can substantially cut down on
++    computation since calculations of unresolved or clipped pixels
++    are skipped.
++
++    The interface of ModestImage is the same as AxesImage. However, it
++    does not currently support setting the 'extent' property. There
++    may also be weird coordinate warping operations for images that
++    I'm not aware of. Don't expect those to work either.
++
++    Author: Chris Beaumont <beaumont at hawaii.edu>
++    """
++    def __init__(self, *args, **kwargs):
++        #why???
++        #if 'extent' in kwargs and kwargs['extent'] is not None:
++        #    raise NotImplementedError("ModestImage does not support extents")
++
++        self._full_res = None
++        self._sx, self._sy = None, None
++        self._bounds = (None, None, None, None)
++        super(ModestImage, self).__init__(*args, **kwargs)
++
++    def set_data(self, A):
++        """
++        Set the image array
++
++        ACCEPTS: numpy/PIL Image A
++        """
++        self._full_res = A
++        self._A = A
++
++        if self._A.dtype != np.uint8 and not np.can_cast(self._A.dtype,
++                                                         np.float):
++            raise TypeError("Image data can not convert to float")
++
++        if (self._A.ndim not in (2, 3) or
++            (self._A.ndim == 3 and self._A.shape[-1] not in (3, 4))):
++            raise TypeError("Invalid dimensions for image data")
++
++        self._imcache =None
++        self._rgbacache = None
++        self._oldxslice = None
++        self._oldyslice = None
++        self._sx, self._sy = None, None
++
++    def get_array(self):
++        """Override to return the full-resolution array"""
++        return self._full_res
++
++    def _scale_to_res(self):
++        """ Change self._A and _extent to render an image whose
++        resolution is matched to the eventual rendering."""
++
++        ax = self.axes
++        ext = ax.transAxes.transform([1, 1]) - ax.transAxes.transform([0, 0])
++        xlim, ylim = ax.get_xlim(), ax.get_ylim()
++        dx, dy = xlim[1] - xlim[0], ylim[1] - ylim[0]
++
++        y0 = max(0, ylim[0] - 5)
++        y1 = min(self._full_res.shape[0], ylim[1] + 5)
++        x0 = max(0, xlim[0] - 5)
++        x1 = min(self._full_res.shape[1], xlim[1] + 5)
++        y0, y1, x0, x1 = map(int, [y0, y1, x0, x1])
++
++        sy = int(max(1, min((y1 - y0) / 5., np.ceil(dy / ext[1]))))
++        sx = int(max(1, min((x1 - x0) / 5., np.ceil(dx / ext[0]))))
++
++        # have we already calculated what we need?
++        if sx == self._sx and sy == self._sy and \
++            x0 == self._bounds[0] and x1 == self._bounds[1] and \
++            y0 == self._bounds[2] and y1 == self._bounds[3]:
++            return
++
++        self._A = self._full_res[y0:y1:sy, x0:x1:sx]
++        self._A = cbook.safe_masked_invalid(self._A)
++        x1 = x0 + self._A.shape[1] * sx
++        y1 = y0 + self._A.shape[0] * sy
++
++        self.set_extent([x0 - .5, x1 - .5, y0 - .5, y1 - .5])
++        self._sx = sx
++        self._sy = sy
++        self._bounds = (x0, x1, y0, y1)
++        self.changed()
++
++    def draw(self, renderer, *args, **kwargs):
++        self._scale_to_res()
++        super(ModestImage, self).draw(renderer, *args, **kwargs)
++
++
++def imshow(axes, X, cmap=None, norm=None, aspect=None,
++           interpolation=None, alpha=None, vmin=None, vmax=None,
++           origin=None, extent=None, shape=None, filternorm=1,
++           filterrad=4.0, imlim=None, resample=None, url=None, **kwargs):
++    """Similar to matplotlib's imshow command, but produces a ModestImage
++
++    Unlike matplotlib version, must explicitly specify axes
++    Author: Chris Beaumont <beaumont at hawaii.edu>
++    """
++
++    if not axes._hold:
++        axes.cla()
++    if norm is not None:
++        assert(isinstance(norm, mcolors.Normalize))
++    if aspect is None:
++        aspect = rcParams['image.aspect']
++    axes.set_aspect(aspect)
++    im = ModestImage(axes, cmap, norm, interpolation, origin, extent,
++                            filternorm=filternorm,
++                            filterrad=filterrad, resample=resample, **kwargs)
++
++    im.set_data(X)
++    im.set_alpha(alpha)
++    axes._set_artist_props(im)
++
++    if im.get_clip_path() is None:
++        # image does not already have clipping set, clip to axes patch
++        im.set_clip_path(axes.patch)
++
++    #if norm is None and shape is None:
++    #    im.set_clim(vmin, vmax)
++    if vmin is not None or vmax is not None:
++        im.set_clim(vmin, vmax)
++    else:
++        im.autoscale_None()
++    im.set_url(url)
++
++    # update ax.dataLim, and, if autoscaling, set viewLim
++    # to tightly fit the image, regardless of dataLim.
++    im.set_extent(im.get_extent())
++
++    axes.images.append(im)
++    im._remove_method = lambda h: axes.images.remove(h)
++
++    return im
+\ No newline at end of file
 Index: gui/wxpython/scatt_plot/controllers.py
 ===================================================================
 --- gui/wxpython/scatt_plot/controllers.py	(revision 0)
@@ -712,6 +1547,50 @@
 +
 +        self.Bind(EVT_CMD_DONE, self.OnThreadDone)
 +
++    def OnThreadDone(self, event):
++        
++        if event.exception:
++            GError(str(event.exception))
++            return
++
++        if event.pid in self.tasks_pids['mapwin_conn']:
++            self.tasks_pids['mapwin_conn'].remove(event.pid)
++            updated_cats = event.ret
++
++            for cat in updated_cats:
++                if cat not in  self.cats_to_update:
++                    self.cats_to_update.append(cat)
++
++            if not self.tasks_pids['mapwin_conn']:
++                self.tasks_pids['render_plots'] = self.thread.GetId()
++                self.thread.Run(callable = self.core.ComputeCatsScatts, 
++                                cats_ids = self.cats_to_update[:])
++                del self.cats_to_update[:]
++ 
++            return
++
++        if self.tasks_pids['render_plots'] == event.pid:
++            self.RenderScattPlts()
++            return
++            
++        if event.pid in self.tasks_pids['add_scatt']:
++            self.tasks_pids['add_scatt'].remove(event.pid)
++            self.AddScattPlotDone(event)
++            return
++
++        if self.tasks_pids['set_data'] == event.pid:
++            self.SetDataDone(event)
++            return
++        
++        if self.tasks_pids['set_data_add'] == event.pid:
++            self.SetDataDone(event)
++            self.AddScattPlot()
++            return
++        
++        if self.tasks_pids['set_edit_cat_data'] == event.pid:
++            self.SetEditCatDataDone(event)
++            return
++
 +    def SetData(self, bands):
 +        self.data_set = False
 +
@@ -814,50 +1693,6 @@
 +            scatt.CleanUp()
 +            del self.plots[scatt_id]
 +
-+    def OnThreadDone(self, event):
-+        
-+        if event.exception:
-+            GError(str(event.exception))
-+            return
-+
-+        if event.pid in self.tasks_pids['mapwin_conn']:
-+            self.tasks_pids['mapwin_conn'].remove(event.pid)
-+            updated_cats = event.ret
-+
-+            for cat in updated_cats:
-+                if cat not in  self.cats_to_update:
-+                    self.cats_to_update.append(cat)
-+
-+            if not self.tasks_pids['mapwin_conn']:
-+                self.tasks_pids['render_plots'] = self.thread.GetId()
-+                self.thread.Run(callable = self.core.ComputeCatsScatts, 
-+                                cats_ids = self.cats_to_update[:])
-+                del self.cats_to_update[:]
-+ 
-+            return
-+
-+        if self.tasks_pids['render_plots'] == event.pid:
-+            self.RenderScattPlts()
-+            return
-+            
-+        if event.pid in self.tasks_pids['add_scatt']:
-+            self.tasks_pids['add_scatt'].remove(event.pid)
-+            self.AddScattPlotDone(event)
-+            return
-+
-+        if self.tasks_pids['set_data'] == event.pid:
-+            self.SetDataDone(event)
-+            return
-+        
-+        if self.tasks_pids['set_data_add'] == event.pid:
-+            self.SetDataDone(event)
-+            self.AddScattPlot()
-+            return
-+        
-+        if self.tasks_pids['set_edit_cat_data'] == event.pid:
-+            self.SetEditCatDataDone(event)
-+            return
-+
 +    def SetPlotsMode(self, mode):
 +
 +        self.plot_mode = mode
@@ -1239,7 +2074,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/gthreading.py	(revision 0)
 +++ gui/wxpython/scatt_plot/gthreading.py	(working copy)
-@@ -0,0 +1,134 @@
+@@ -0,0 +1,133 @@
 +"""!
 + at package scatt_plot.gthreading
 +
@@ -1358,8 +2193,7 @@
 +            time.sleep(.1)
 +
 +            if self.receiver:
-+                event = wxCmdDone(type = 'cmd',
-+                                  kwds = kwds,
++                event = wxCmdDone(kwds = kwds,
 +                                  args = args, #TODO expand args to kwds
 +                                  ret=ret,
 +                                  exception=exception,
@@ -1650,23 +2484,23 @@
 +        """
 +        self.icons = {
 +            'sel_add'         : MetaIcon(img = 'layer-add',
-+                                         label = _('Include selected areas from category.'),
-+                                         desc = _('Include selected areas from category.')),
++                                         label = _('Include selected area to class.'),
++                                         desc = _('Include selected area to class.')),
 +            'sel_remove'      : MetaIcon(img = 'layer-remove',
-+                                         label = _('Exclude selected areas from category.'),
-+                                         desc = _('Exclude selected areas from category.')),
++                                         label = _('Exclude selected area from class.'),
++                                         desc = _('Exclude selected area from class.')),
 +            'addVertex'       : MetaIcon(img = 'vertex-create',
 +                                         label = _('Add new vertex'),
 +                                         desc = _('Add new vertex to polygon boundary scatter plot')),
 +            'editLine'        : MetaIcon(img = 'line-edit',
 +                                         label = _('Edit line/boundary'),
-+                                         desc = _('Add new vertex to last point of the boundary')),
++                                         desc = _('Add new vertex between last and first points of the boundary')),
 +            'moveVertex'      : MetaIcon(img = 'vertex-move',
 +                                         label = _('Move vertex'),
 +                                         desc = _('Move boundary vertex')),
 +            'removeVertex'    : MetaIcon(img = 'vertex-delete',
 +                                         label = _('Remove vertex'),
-+                                         desc = _('Remove vertex.')),
++                                         desc = _('Remove boundary vertex.')),
 +            }
 +
 +        return self._getToolbarData((
@@ -2495,679 +3329,9 @@
 +
 +    return scatt_id
 +
-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,166 @@
-+"""!
-+ 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)
-+"""
-+
-+import sys
-+from multiprocessing import Process, Queue
-+
-+from ctypes import *
-+try:
-+    from grass.lib.imagery import *
-+    from grass.lib.gis import Cell_head, G_get_window
-+except ImportError, e:
-+    sys.stderr.write(_("Loading imagery lib failed"))
-+
-+from core.gcmd import GException
-+
-+
-+def ComputeScatts(region, scatt_conds, bands, n_bands, scatts, cats_rasts_conds, cats_rasts):
-+    q = Queue()
-+    p = Process(target=_computeScattsProcess, args=(region, scatt_conds, bands, 
-+                                                    n_bands, scatts, cats_rasts_conds, cats_rasts, q))
-+    p.start()
-+    ret = q.get()
-+    p.join()
-+
-+    return ret[0], ret[1]
-+
-+def UpdateCatRast(patch_rast, region, cat_rast):
-+    q = Queue()
-+    p = Process(target=_updateCatRastProcess, args=(patch_rast, region, cat_rast, q))
-+    p.start()
-+    ret = q.get()
-+    p.join()
-+
-+    return ret
-+
-+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_conds, cats_rasts, output_queue):
-+
-+    #TODO names for types not 0 and 1?
-+    sccats_c, cats_rasts_c, refs = _getComputationStruct(scatts, cats_rasts, 0, n_bands)
-+    scatt_conds_c, cats_rasts_conds_c, refs2 = _getComputationStruct(scatt_conds, cats_rasts_conds, 1, n_bands)
-+
-+    char_bands = _stringListToCharArr(bands)
-+   
-+    cell_head = _regionToCellHead(region)
-+
-+    ret = I_compute_scatts(pointer(cell_head),
-+                           pointer(scatt_conds_c),
-+                           pointer(cats_rasts_conds_c),
-+                           pointer(char_bands),
-+                           n_bands,
-+                           pointer(sccats_c),
-+                           pointer(cats_rasts_c))
-+
-+    I_sc_free_cats(pointer(sccats_c))
-+    I_sc_free_cats(pointer(scatt_conds_c))
-+
-+    output_queue.put((ret, scatts))
-+
-+def _getBandcRange( band_info):
-+    band_c_range = struct_Range()
-+
-+    band_c_range.max = band_info['max']
-+    band_c_range.min = band_info['min']
-+
-+    return band_c_range
-+
-+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_rasts, cats_type, n_bands):
-+
-+    sccats = struct_scCats()
-+    I_sc_init_cats(pointer(sccats), c_int(n_bands), c_int(cats_type));
-+
-+    refs = []        
-+    cats_rasts_core = []
-+    
-+    for cat_id, scatt_ids in cats.iteritems():
-+        cat_c_id = I_sc_add_cat(pointer(sccats))
-+        cats_rasts_core.append(cats_rasts[cat_id])
-+
-+        for scatt_id, dt in scatt_ids.iteritems():
-+            # if key is missing condition is always True (full scatter plor is computed)
-+                vals = dt['np_vals']
-+
-+                scatt_vals = scdScattData()
-+
-+                c_void_p = ctypes.POINTER(ctypes.c_void_p)
-+
-+                if cats_type == SC_SCATT_DATA:
-+                    vals[:] = 0
-+                elif cats_type == SC_SCATT_CONDITIONS:
-+                    pass
-+                else:
-+                    return None
-+                data_p = vals.ctypes.data_as(c_void_p)
-+                I_scd_init_scatt_data(pointer(scatt_vals), cats_type, len(vals), data_p)
-+
-+                refs.append(scatt_vals)
-+
-+                I_sc_insert_scatt_data(pointer(sccats),  
-+                                       pointer(scatt_vals),
-+                                       cat_c_id, scatt_id)
-+
-+    cats_rasts_c = _stringListToCharArr(cats_rasts_core)
-+
-+    return sccats, cats_rasts_c, refs
-+
-+def _updateCatRastProcess(patch_rast, region, cat_rast, output_queue):
-+    cell_head = _regionToCellHead(region)
-+    
-+    
-+    ret = I_insert_patch_to_cat_rast(patch_rast, 
-+                                     pointer(cell_head), 
-+                                     cat_rast)
-+
-+    output_queue.put(ret)
-+
-+
-Index: gui/wxpython/scatt_plot/frame.py
-===================================================================
---- gui/wxpython/scatt_plot/frame.py	(revision 0)
-+++ gui/wxpython/scatt_plot/frame.py	(working copy)
-@@ -0,0 +1,494 @@
-+"""!
-+ at package scatt_plot.dialogs
-+
-+ at brief GUI.
-+
-+Classes:
-+
-+(C) 2013 by the GRASS Development Team
-+
-+This program is free software under the GNU General Public License
-+(>=v2). Read the file COPYING that comes with GRASS for details.
-+
-+ at author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
-+"""
-+import os
-+import sys
-+
-+import wx
-+import wx.lib.scrolledpanel as scrolled
-+import wx.lib.mixins.listctrl as listmix
-+import wx.lib.flatnotebook  as FN
-+import wx.aui
-+
-+from core import globalvar
-+from core.gcmd import GException, GError, RunCommand
-+
-+from gui_core.gselect import Select
-+
-+from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars import MainToolbar, EditingToolbar
-+from scatt_plot.scatt_core import idScattToidBands
-+from scatt_plot.plots import ScatterPlotWidget
-+
-+try:
-+    from agw import aui
-+except ImportError:
-+    import wx.lib.agw.aui as aui
-+
-+class IClassScatterPlotsPanel(wx.Panel):
-+    def __init__(self, parent, giface, iclass_mapwin = None,
-+                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
-+
-+        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
-+        #                           style = wx.SP_LIVE_UPDATE)
-+        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
-+
-+        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
-+        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
-+
-+        # toobars
-+        self.toolbars = {}
-+        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
-+        self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
-+        
-+        self._createCategoryPanel(self)
-+
-+        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
-+
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
-+        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
-+
-+        self.catsPanel.Hide()
-+        self.toolbars['editingToolbar'].Hide()
-+
-+        self.SetSizer(mainsizer)
-+        
-+        #self.SetSashGravity(0.5)
-+        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
-+        self.Layout()
-+
-+    def NewScatterPlot(self, scatt_id):
-+        return self.plot_panel.NewScatterPlot(scatt_id)
-+
-+    def ShowPlotEditingToolbar(self, show):
-+        self.toolbars["editingToolbar"].Show(show)
-+        self.Layout()
-+
-+    def ShowCategoryPanel(self, show):
-+        self.catsPanel.Show(show)
-+        
-+        #if show:
-+        #    self.SetSashSize(5) 
-+        #else:
-+        #    self.SetSashSize(0)
-+        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
-+        self.Layout()
-+
-+    def _createCategoryPanel(self, parent):
-+        self.catsPanel = wx.Panel(parent = parent)
-+        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
-+                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
-+
-+        self.catsPanel.SetMaxSize((-1, 150))
-+
-+        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
-+                             label = ' %s ' % _("Classes manager for scatter plots"))
-+        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
-+
-+        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
-+        self.catsPanel.SetSizer(catsSizer)
-+
-+
-+class IClassPlotPanel(scrolled.ScrolledPanel):
-+    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
-+    
-+        scrolled.ScrolledPanel.__init__(self, parent)
-+        self.SetupScrolling(scroll_x = False, scroll_y = True, scrollToTop = False)
-+
-+        self.scatt_mgr = scatt_mgr
-+
-+        self.mainPanel = wx.Panel(parent = self, id = wx.ID_ANY)
-+
-+        #self._createCategoryPanel()
-+        # Fancy gui
-+        self._mgr = aui.AuiManager(self.mainPanel)
-+        #self._mgr.SetManagedWindow(self)
-+
-+        self._mgr.Update()
-+
-+        self._doLayout()
-+        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
-+        self.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged)
-+
-+        self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed)
-+
-+        dlgSize = (-1, 400)
-+        #self.SetBestSize(dlgSize)
-+        #self.SetInitialSize(dlgSize)
-+        self.SetAutoLayout(1)
-+        #fix goutput's pane size (required for Mac OSX)
-+        #if self.gwindow:         
-+        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
-+        self.ignore_scroll = 0
-+        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
-+
-+    def OnMouseWheel(self, event):
-+        #TODO very ugly find some better solution        
-+        self.ignore_scroll = 3
-+        event.Skip()
-+
-+    def ScrollChildIntoView(self, child):
-+        #For aui manager it does not work and returns position always to the top -> deactivated.
-+        pass
-+
-+    def OnPlotPaneClosed(self, event):
-+        if isinstance(event.pane.window, ScatterPlotWidget):
-+            event.pane.window.CleanUp()
-+
-+    def OnScrollChanged(self, event):
-+        print "changed"
-+        wx.CallAfter(self.Layout)
-+
-+
-+    def OnScroll(self, event):
-+        if self.ignore_scroll > 0:
-+            self.ignore_scroll -= 1
-+        else:
-+            event.Skip()
-+
-+        #wx.CallAfter(self._mgr.Update)
-+        #wx.CallAfter(self.Layout)
-+
-+    def _doLayout(self):
-+
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
-+        self.SetSizer(mainsizer)
-+
-+        self.Layout()
-+        self.SetupScrolling()
-+
-+    def OnCloseDialog(self, event):
-+        """!Close dialog"""
-+        self.scatt_mgr.CleanUp()
-+        self.Destroy()
-+
-+    def OnSettings(self, event):
-+        pass
-+
-+    def NewScatterPlot(self, scatt_id):
-+        #TODO needs to be resolved (should be in this class)
-+
-+        scatt = ScatterPlotWidget(parent = self.mainPanel, 
-+                                  scatt_mgr = self.scatt_mgr, 
-+                                  scatt_id = scatt_id)
-+
-+        bands = self.scatt_mgr.GetBands()
-+        #TODO too low level
-+        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
-+
-+        self._mgr.AddPane(scatt,
-+                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
-+                           Name("scatter plot %d" % scatt_id).MinSize((-1, 300)).Caption(("%s x: %s y: %s") % (_("scatter plot"), bands[b1_id], bands[b2_id])).
-+                           Center().Position(1).MaximizeButton(True).
-+                           MinimizeButton(True).CaptionVisible(True).
-+                           CloseButton(True).Layer(0))
-+        
-+
-+        self._mgr.Update()
-+  
-+        self.SetVirtualSize(self.GetBestVirtualSize())
-+        self.Layout()
-+
-+        return scatt
-+
-+    def GetScattMgr(self):
-+        return  self.scatt_mgr
-+
-+class CategoryListCtrl(wx.ListCtrl,
-+                       listmix.ListCtrlAutoWidthMixin,
-+                       listmix.TextEditMixin):
-+
-+    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
-+
-+        wx.ListCtrl.__init__(self, parent, id,
-+                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
-+        self.columns = ((_('Class name'), 'name'),
-+                        (_('Color'), 'color'))
-+        self.Populate(columns = self.columns)
-+        
-+        self.cats_mgr = cats_mgr
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+
-+        self.rightClickedItemIdx = wx.NOT_FOUND
-+        
-+        listmix.ListCtrlAutoWidthMixin.__init__(self)
-+
-+        listmix.TextEditMixin.__init__(self)
-+        
-+        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
-+        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
-+             
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+        self.cats_mgr.deletedCategory.connect(self.Update)
-+        self.cats_mgr.addedCategory.connect(self.Update)
-+
-+    def Update(self, **kwargs):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+    def InitCoreCats(self):
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
-+
-+    def SetVirtualData(self, row, column, text):
-+        attr = self.columns[column][1]
-+        if attr == 'name':
-+            try:
-+                text.encode('ascii')
-+            except UnicodeEncodeError:
-+                GMessage(parent = self, message = _("Please use only ASCII characters."))
-+                return
-+
-+        cat_id = self.cats_mgr.GetCategories()[row]
-+
-+        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
-+        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
-+        self.cats_mgr.setCategoryAttrs.connect(self.Update)
-+        
-+        self.Select(row)
-+        
-+    def Populate(self, columns):
-+        for i, col in enumerate(columns):
-+            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
-+
-+        self.SetColumnWidth(0, 100)
-+        self.SetColumnWidth(1, 100)
-+        
-+    def AddCategory(self):
-+
-+        self.cats_mgr.addedCategory.disconnect(self.Update)
-+        cat_id = self.cats_mgr.AddCategory()
-+        self.cats_mgr.addedCategory.connect(self.Update)
-+
-+        if cat_id < 0:
-+            GError(_("Maximum limit of categories number was reached."))
-+            return
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+                        
-+    def DeleteCategory(self):
-+        indexList = sorted(self.GetSelectedIndices(), reverse = True)
-+        cats = []
-+        for i in indexList:
-+            # remove temporary raster
-+            cat_id = self.cats_mgr.GetCategories()[i]
-+            
-+            cats.append(cat_id)
-+
-+            self.cats_mgr.deletedCategory.disconnect(self.Update)
-+            self.cats_mgr.DeleteCategory(cat_id)
-+            self.cats_mgr.deletedCategory.connect(self.Update)
-+            
-+        self.SetItemCount(len(self.cats_mgr.GetCategories()))
-+        
-+    def OnSel(self, event): 
-+        event.Skip()
-+
-+    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-+        indices = []
-+        lastFound = -1
-+        while True:
-+            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
-+            if index == -1:
-+                break
-+            else:
-+                lastFound = index
-+                indices.append(index)
-+        return indices        
-+
-+    def OnEdit(self, event):
-+        currentItem = event.m_itemIndex
-+        currentCol = event.m_col
-+
-+        if currentCol == 1:
-+            dlg = wx.ColourDialog(self)
-+            dlg.GetColourData().SetChooseFull(True)
-+
-+            if dlg.ShowModal() == wx.ID_OK:
-+                color = dlg.GetColourData().GetColour().Get()
-+                color = ':'.join(map(str, color))
-+                self.SetVirtualData(currentItem, currentCol, color)
-+            dlg.Destroy()
-+            wx.CallAfter(self.SetFocus)
-+        
-+        event.Skip()
-+        
-+        
-+    def DeselectAll(self):
-+        """!Deselect all items"""
-+        indexList = self.GetSelectedIndices()
-+        for i in indexList:
-+            self.Select(i, on = 0)
-+         
-+        # no highlight
-+        self.OnCategorySelected(None)
-+        
-+    def OnGetItemText(self, item, col):
-+        attr = self.columns[col][1]
-+        cat_id = self.cats_mgr.GetCategories()[item]
-+
-+        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
-+
-+    def OnGetItemImage(self, item):
-+        return -1
-+
-+    def OnGetItemAttr(self, item):
-+        return None
-+
-+    def OnClassRightUp(self, event):
-+        """!Show context menu on right click"""
-+        item, flags = self.HitTest((event.GetX(), event.GetY()))
-+        if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
-+            self.rightClickedItemIdx = item
-+           
-+        self.popupZoomtoAreas = wx.NewId()
-+        self.Bind(wx.EVT_MENU, self.OnZoomToAreasByCat, id = self.popupZoomtoAreas)
-+
-+        # generate popup-menu
-+        menu = wx.Menu()
-+        menu.Append(self.popupZoomtoAreas, _("Zoom to training areas of selected class"))
-+        
-+        self.PopupMenu(menu)
-+        menu.Destroy()
-+    
-+    def OnZoomToAreasByCat(self, event):
-+        """!Zoom to areas of given category"""
-+        cat = self.stats_data.GetCategories()[self.rightClickedItemIdx]
-+        self.mapWindow.ZoomToAreasByCat(cat)
-+
-+class AddScattPlotDialog(wx.Dialog):
-+
-+    def __init__(self, parent, bands, id  = wx.ID_ANY):
-+        
-+        wx.Dialog.__init__(self, parent, title = ("Add scatter plot"), id = id)
-+
-+        self.bands = bands
-+
-+        self.scatt_id = None
-+
-+        self._createWidgets()
-+
-+    def _createWidgets(self):
-+
-+        self.labels = {}
-+        self.params = {}
-+
-+        self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 1:"))
-+
-+        self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Band 2:"))
-+
-+        self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
-+                                     choices = self.bands,
-+                                     style = wx.CB_READONLY, size = (350, 30))
-+
-+        # buttons
-+        self.btn_close = wx.Button(parent = self, id = wx.ID_CANCEL)
-+        
-+        self.btn_ok = wx.Button(parent = self, id = wx.ID_OK, label = _("&OK"))
-+
-+        self._layout()
-+
-+    def _layout(self):
-+
-+        border = wx.BoxSizer(wx.VERTICAL) 
-+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
-+
-+        regionSizer = wx.BoxSizer(wx.HORIZONTAL)
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label, 
-+                                                    sel = self.band_1_ch))
-+
-+        dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label, 
-+                                                    sel = self.band_2_ch))
-+
-+        # buttons
-+        self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
-+
-+        self.btnsizer.Add(item = self.btn_close, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+        
-+        self.btnsizer.Add(item = self.btn_ok, proportion = 0,
-+                          flag = wx.ALL | wx.ALIGN_CENTER,
-+                          border = 10)
-+
-+        dialogSizer.Add(item = self.btnsizer, proportion = 0,
-+                        flag = wx.ALIGN_CENTER)
-+
-+        border.Add(item = dialogSizer, proportion = 0,
-+                   flag = wx.ALL, border = 5)
-+
-+        self.SetSizer(border)
-+        self.Layout()
-+        self.Fit()
-+
-+        # bindings
-+        self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
-+        self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
-+
-+    def _addSelectSizer(self, title, sel): 
-+        """!Helper layout function.
-+        """
-+        selSizer = wx.BoxSizer(orient = wx.VERTICAL)
-+
-+        selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
-+        selTitleSizer.Add(item = title, proportion = 1,
-+                          flag = wx.LEFT | wx.TOP | wx.EXPAND, border = 5)
-+
-+        selSizer.Add(item = selTitleSizer, proportion = 0,
-+                     flag = wx.EXPAND)
-+
-+        selSizer.Add(item = sel, proportion = 1,
-+                     flag = wx.EXPAND | wx.ALL| wx.ALIGN_CENTER_VERTICAL,
-+                     border = 5)
-+
-+        return selSizer
-+
-+    def OnClose(self, event):
-+        """!Close dialog
-+        """
-+        if not self.IsModal():
-+            self.Destroy()
-+        event.Skip()
-+
-+    def OnOk(self, event):
-+        """!
-+        """
-+        band_1 = self.band_1_ch.GetSelection()
-+        band_2 = self.band_2_ch.GetSelection()
-+
-+
-+        if band_1 == band_2:
-+            GError(_("Selected bands must be different."))
-+            return
-+        
-+        #TODO axes selection
-+        if band_1 > band_2:
-+            tmp_band = band_2
-+            band_2 = band_1
-+            band_1 = band_2
-+
-+        self.scatt_id = idBandsToidScatt(band_1, band_2, len(self.bands))
-+
-+        event.Skip()
-+
-+    def GetScattId(self):
-+        return self.scatt_id
 Index: gui/wxpython/Makefile
 ===================================================================
---- gui/wxpython/Makefile	(revision 57506)
+--- gui/wxpython/Makefile	(revision 57529)
 +++ gui/wxpython/Makefile	(working copy)
 @@ -13,7 +13,7 @@
  	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
@@ -3191,7 +3355,7 @@
  default: $(DSTFILES)
 Index: gui/wxpython/vdigit/wxdigit.py
 ===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57506)
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57529)
 +++ gui/wxpython/vdigit/wxdigit.py	(working copy)
 @@ -17,7 +17,7 @@
  (and NumPy would be an excellent candidate for acceleration via
@@ -3711,7 +3875,7 @@
      def GetLineCats(self, line):
 Index: gui/wxpython/vdigit/toolbars.py
 ===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57506)
+--- gui/wxpython/vdigit/toolbars.py	(revision 57529)
 +++ gui/wxpython/vdigit/toolbars.py	(working copy)
 @@ -17,6 +17,7 @@
  import wx
@@ -3738,55 +3902,34 @@
          return True
  
      def StopEditing(self):
-Index: gui/wxpython/mapdisp/toolbars.py
+Index: gui/wxpython/iclass/dialogs.py
 ===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57506)
-+++ gui/wxpython/mapdisp/toolbars.py	(working copy)
-@@ -239,7 +239,8 @@
-                       (MapIcons["scatter"],     self.parent.OnScatterplot),
-                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
-                       (BaseIcons["histogramD"], self.parent.OnHistogram),
--                      (MapIcons["vnet"],        self.parent.OnVNet)))
-+                      (MapIcons["vnet"],        self.parent.OnVNet),
-+                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
-         
-     def OnDecoration(self, event):
-         """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
-===================================================================
---- gui/wxpython/mapdisp/frame.py	(revision 57506)
-+++ gui/wxpython/mapdisp/frame.py	(working copy)
-@@ -225,6 +225,7 @@
-         #
-         self.dialogs = {}
-         self.dialogs['attributes'] = None
-+        self.dialogs['scatt_plot'] = None
-         self.dialogs['category'] = None
-         self.dialogs['barscale'] = None
-         self.dialogs['legend'] = None
-@@ -1168,6 +1169,19 @@
-         """!Returns toolbar with zooming tools"""
-         return self.toolbars['map']
- 
-+    def OnScatterplot2(self, event):
-+        """!Init interactive scatterplot tools
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
+--- gui/wxpython/iclass/dialogs.py	(revision 57529)
++++ gui/wxpython/iclass/dialogs.py	(working copy)
+@@ -333,13 +333,19 @@
+         toolbar.SetCategories(catNames = catNames, catIdx = cats)
+         if name in catNames:
+             toolbar.choice.SetStringSelection(name)
++            cat = toolbar.GetSelectedCategoryIdx()
+         elif catNames:
+             toolbar.choice.SetSelection(0)
+-            
++            cat = toolbar.GetSelectedCategoryIdx()
++        else:
++            cat = None
 +
-+        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()
+         if toolbar.choice.IsEmpty():
+             toolbar.EnableControls(False)
+         else:
+             toolbar.EnableControls(True)
 +
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
++        self.mapWindow.CategoryChanged(cat)
+         # don't forget to update maps, histo, ...
+         
+     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
 Index: gui/wxpython/iclass/toolbars.py
 ===================================================================
---- gui/wxpython/iclass/toolbars.py	(revision 57506)
+--- gui/wxpython/iclass/toolbars.py	(revision 57529)
 +++ gui/wxpython/iclass/toolbars.py	(working copy)
 @@ -46,9 +46,7 @@
          'importAreas' : MetaIcon(img = 'layer-import',
@@ -3822,7 +3965,7 @@
                                        self.parent.OnCategoryManager),
 Index: gui/wxpython/iclass/frame.py
 ===================================================================
---- gui/wxpython/iclass/frame.py	(revision 57506)
+--- gui/wxpython/iclass/frame.py	(revision 57529)
 +++ gui/wxpython/iclass/frame.py	(working copy)
 @@ -64,6 +64,8 @@
                                 IClassExportAreasDialog, IClassMapDialog
@@ -3942,7 +4085,7 @@
      
 Index: gui/wxpython/iclass/plots.py
 ===================================================================
---- gui/wxpython/iclass/plots.py	(revision 57506)
+--- gui/wxpython/iclass/plots.py	(revision 57529)
 +++ gui/wxpython/iclass/plots.py	(working copy)
 @@ -28,7 +28,7 @@
      for each band and for one category. Coincidence plots show min max range
@@ -4074,46 +4217,52 @@
      def DrawCoincidencePlots(self):
          """!Draw coincidence plots"""
          for bandIdx in range(len(self.bandList)):
-Index: gui/wxpython/iclass/dialogs.py
+Index: gui/wxpython/mapdisp/toolbars.py
 ===================================================================
---- gui/wxpython/iclass/dialogs.py	(revision 57506)
-+++ gui/wxpython/iclass/dialogs.py	(working copy)
-@@ -333,13 +333,19 @@
-         toolbar.SetCategories(catNames = catNames, catIdx = cats)
-         if name in catNames:
-             toolbar.choice.SetStringSelection(name)
-+            cat = toolbar.GetSelectedCategoryIdx()
-         elif catNames:
-             toolbar.choice.SetSelection(0)
--            
-+            cat = toolbar.GetSelectedCategoryIdx()
-+        else:
-+            cat = None
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57529)
++++ gui/wxpython/mapdisp/toolbars.py	(working copy)
+@@ -239,7 +239,8 @@
+                       (MapIcons["scatter"],     self.parent.OnScatterplot),
+                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
+                       (BaseIcons["histogramD"], self.parent.OnHistogram),
+-                      (MapIcons["vnet"],        self.parent.OnVNet)))
++                      (MapIcons["vnet"],        self.parent.OnVNet),
++                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
+         
+     def OnDecoration(self, event):
+         """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py	(revision 57529)
++++ gui/wxpython/mapdisp/frame.py	(working copy)
+@@ -225,6 +225,7 @@
+         #
+         self.dialogs = {}
+         self.dialogs['attributes'] = None
++        self.dialogs['scatt_plot'] = None
+         self.dialogs['category'] = None
+         self.dialogs['barscale'] = None
+         self.dialogs['legend'] = None
+@@ -1168,6 +1169,19 @@
+         """!Returns toolbar with zooming tools"""
+         return self.toolbars['map']
+ 
++    def OnScatterplot2(self, event):
++        """!Init interactive scatterplot tools
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
 +
-         if toolbar.choice.IsEmpty():
-             toolbar.EnableControls(False)
-         else:
-             toolbar.EnableControls(True)
++        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()
 +
-+        self.mapWindow.CategoryChanged(cat)
-         # don't forget to update maps, histo, ...
-         
-     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-Index: lib/vector/Vlib/open.c
-===================================================================
---- lib/vector/Vlib/open.c	(revision 57506)
-+++ lib/vector/Vlib/open.c	(working copy)
-@@ -240,7 +240,9 @@
-         }
-         else {
-             char file_path[GPATH_MAX];
--            
-+            /* reduce to current mapset if search path was set */
-+            if(strcmp(Map->mapset, "") == 0)
-+                Map->mapset = G_store(G_mapset());
-             /* temporary map: reduce to current mapset if search path
-              * was set */
-             if (strcmp(Map->mapset, "") == 0)
+     def OnVNet(self, event):
+         """!Dialog for v.net* modules 
+         """
 Index: lib/imagery/scatt.c
 ===================================================================
 --- lib/imagery/scatt.c	(revision 0)
@@ -5276,3 +5425,18 @@
 +    return 0;
 +}
 +#endif
+Index: lib/vector/Vlib/open.c
+===================================================================
+--- lib/vector/Vlib/open.c	(revision 57529)
++++ lib/vector/Vlib/open.c	(working copy)
+@@ -240,7 +240,9 @@
+         }
+         else {
+             char file_path[GPATH_MAX];
+-            
++            /* reduce to current mapset if search path was set */
++            if(strcmp(Map->mapset, "") == 0)
++                Map->mapset = G_store(G_mapset());
+             /* temporary map: reduce to current mapset if search path
+              * was set */
+             if (strcmp(Map->mapset, "") == 0)



More information about the grass-commit mailing list