浏览代码

wx.iclass: added interface for statistics data

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@57284 15284696-431f-4ddb-bdfa-cd5b030d7da7
Štěpán Turek 11 年之前
父节点
当前提交
ab0c59a793
共有 4 个文件被更改,包括 180 次插入98 次删除
  1. 49 35
      gui/wxpython/iclass/dialogs.py
  2. 31 28
      gui/wxpython/iclass/frame.py
  3. 20 17
      gui/wxpython/iclass/plots.py
  4. 80 18
      gui/wxpython/iclass/statistics.py

+ 49 - 35
gui/wxpython/iclass/dialogs.py

@@ -154,8 +154,8 @@ class IClassCategoryManagerDialog(wx.Dialog):
                            label = " %s " % _("Classes"))
                            label = " %s " % _("Classes"))
         sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
         sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
         gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
         gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
-        self.catList = CategoryListCtrl(panel, mapwindow = parent, statistics = parent.statisticsDict,
-                                         statisticsList = parent.statisticsList)
+        self.catList = CategoryListCtrl(panel, mapwindow = parent, 
+                                               stats_data = parent.stats_data)
         addButton = wx.Button(panel, id = wx.ID_ADD)
         addButton = wx.Button(panel, id = wx.ID_ADD)
         deleteButton = wx.Button(panel, id = wx.ID_DELETE)
         deleteButton = wx.Button(panel, id = wx.ID_DELETE)
         
         
@@ -187,8 +187,8 @@ class IClassCategoryManagerDialog(wx.Dialog):
         self.Layout()
         self.Layout()
 
 
     def OnAddCategory(self, event):
     def OnAddCategory(self, event):
-        if self.parent.statisticsList:
-            cat = max(self.parent.statisticsList) + 1
+        if self.parent.stats_data.GetCategories():
+            cat = max(self.parent.stats_data.GetCategories()) + 1
         else:
         else:
             cat = 1
             cat = 1
         defaultName = 'class' + '_' + str(cat) # intentionally not translatable
         defaultName = 'class' + '_' + str(cat) # intentionally not translatable
@@ -221,16 +221,13 @@ class CategoryListCtrl(wx.ListCtrl,
     when deleting class (category).
     when deleting class (category).
     It uses virtual data in the terms of @c wx.ListCtrl.
     It uses virtual data in the terms of @c wx.ListCtrl.
     
     
-    @todo statistics and categories are managed here directly,
-    it could be better to use some interface
     @todo delete vector features after deleting class
     @todo delete vector features after deleting class
     """
     """
-    def __init__(self, parent, mapwindow, statistics, statisticsList, id = wx.ID_ANY):
+    def __init__(self, parent, mapwindow, stats_data, id = wx.ID_ANY):
         """!
         """!
         @param parent gui parent
         @param parent gui parent
         @param mapwindow mapwindow instance with iclass toolbar and remove raster method
         @param mapwindow mapwindow instance with iclass toolbar and remove raster method
-        @param statistics dictionary of statistics (defined in statistics.py)
-        @param statisticsList list of statistics
+        @param stats_data StatisticsData instance (defined in statistics.py)
         @param id wx id
         @param id wx id
         """
         """
         wx.ListCtrl.__init__(self, parent, id,
         wx.ListCtrl.__init__(self, parent, id,
@@ -239,9 +236,8 @@ class CategoryListCtrl(wx.ListCtrl,
                         (_('Color'), 'color'))
                         (_('Color'), 'color'))
         self.Populate(columns = self.columns)
         self.Populate(columns = self.columns)
         self.mapWindow = mapwindow
         self.mapWindow = mapwindow
-        self.statisticsDict = statistics
-        self.statisticsList = statisticsList
-        self.SetItemCount(len(statisticsList))
+        self.stats_data = stats_data
+        self.SetItemCount(len(self.stats_data.GetCategories()))
         
         
         self.rightClickedItemIdx = wx.NOT_FOUND
         self.rightClickedItemIdx = wx.NOT_FOUND
         
         
@@ -254,7 +250,15 @@ class CategoryListCtrl(wx.ListCtrl,
         
         
         self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnClassRightUp) #wxMSW
         self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnClassRightUp) #wxMSW
         self.Bind(wx.EVT_RIGHT_UP,            self.OnClassRightUp) #wxGTK
         self.Bind(wx.EVT_RIGHT_UP,            self.OnClassRightUp) #wxGTK
-        
+    
+        self.stats_data.statisticsAdded.connect(self.Update)
+        self.stats_data.statisticsDeleted.connect(self.Update)
+        self.stats_data.allStatisticsDeleted.connect(self.Update)
+        self.stats_data.statisticsSet.connect(self.Update)
+
+    def Update(self):
+        self.SetItemCount(len(self.stats_data.GetCategories()))
+
     def SetVirtualData(self, row, column, text):
     def SetVirtualData(self, row, column, text):
         attr = self.columns[column][1]
         attr = self.columns[column][1]
         if attr == 'name':
         if attr == 'name':
@@ -263,7 +267,10 @@ class CategoryListCtrl(wx.ListCtrl,
             except UnicodeEncodeError:
             except UnicodeEncodeError:
                 GMessage(parent = self, message = _("Please use only ASCII characters."))
                 GMessage(parent = self, message = _("Please use only ASCII characters."))
                 return
                 return
-        setattr(self.statisticsDict[self.statisticsList[row]], attr, text)
+
+
+        cat = self.stats_data.GetCategories()[row]
+        self.stats_data.GetStatistics(cat).SetStatistics(stats = {attr : text})
         
         
         self.UpdateChoice()
         self.UpdateChoice()
         toolbar = self.mapWindow.toolbars['iClass']
         toolbar = self.mapWindow.toolbars['iClass']
@@ -284,41 +291,46 @@ class CategoryListCtrl(wx.ListCtrl,
         
         
     def AddCategory(self, cat, name, color):
     def AddCategory(self, cat, name, color):
         """!Add category record (used when importing areas)"""
         """!Add category record (used when importing areas)"""
-        st = Statistics()
-        st.SetBaseStatistics(cat = cat, name = name, color = color)
-        self.statisticsDict[cat] = st
-        self.statisticsList.append(cat)
-        self.SetItemCount(len(self.statisticsList))
+
+        self.stats_data.AddStatistics(cat, name, color)
+        self.SetItemCount(len(self.stats_data.GetCategories()))
         
         
         self.UpdateChoice()
         self.UpdateChoice()
         self.mapWindow.UpdateChangeState(changes = True)
         self.mapWindow.UpdateChangeState(changes = True)
                 
                 
     def DeleteCategory(self):
     def DeleteCategory(self):
         indexList = sorted(self.GetSelectedIndices(), reverse = True)
         indexList = sorted(self.GetSelectedIndices(), reverse = True)
-        cats = []
+        del_cats = []
+        cats = self.stats_data.GetCategories()
+
         for i in indexList:
         for i in indexList:
             # remove temporary raster
             # remove temporary raster
-            name = self.statisticsDict[self.statisticsList[i]].rasterName
+            cat = cats[i]
+            stat = self.stats_data.GetStatistics(cat)
+
+            name = stat.rasterName
             self.mapWindow.RemoveTempRaster(name)
             self.mapWindow.RemoveTempRaster(name)
             
             
-            cats.append(self.statisticsList[i])
-            del self.statisticsDict[self.statisticsList[i]]
-            del self.statisticsList[i]
+            del_cats.append(cat)
+            self.stats_data.DeleteStatistics(cat)
             
             
-        self.SetItemCount(len(self.statisticsList))
+        self.SetItemCount(len(self.stats_data.GetCategories()))
         
         
         self.UpdateChoice()
         self.UpdateChoice()
         self.mapWindow.UpdateChangeState(changes = True)
         self.mapWindow.UpdateChangeState(changes = True)
         
         
-        self.mapWindow.DeleteAreas(cats = cats)
+        self.mapWindow.DeleteAreas(cats = del_cats)
     
     
     def UpdateChoice(self):
     def UpdateChoice(self):
         toolbar = self.mapWindow.toolbars['iClass']
         toolbar = self.mapWindow.toolbars['iClass']
         name = toolbar.GetSelectedCategoryName()
         name = toolbar.GetSelectedCategoryName()
         catNames = []
         catNames = []
-        for cat in self.statisticsList:
-            catNames.append(self.statisticsDict[cat].name)
-        toolbar.SetCategories(catNames = catNames, catIdx = self.statisticsList)
+
+        cats = self.stats_data.GetCategories()
+        for cat in cats:
+            stat = self.stats_data.GetStatistics(cat)
+            catNames.append(stat.name)
+        toolbar.SetCategories(catNames = catNames, catIdx = cats)
         if name in catNames:
         if name in catNames:
             toolbar.choice.SetStringSelection(name)
             toolbar.choice.SetStringSelection(name)
         elif catNames:
         elif catNames:
@@ -361,11 +373,12 @@ class CategoryListCtrl(wx.ListCtrl,
     def OnCategorySelected(self, event):
     def OnCategorySelected(self, event):
         """!Highlight selected areas"""
         """!Highlight selected areas"""
         indexList = self.GetSelectedIndices()
         indexList = self.GetSelectedIndices()
-        cats = []
+        sel_cats = []
+        cats = self.stats_data.GetCategories()
         for i in indexList:
         for i in indexList:
-            cats.append(self.statisticsList[i])
+            sel_cats.append(cats[i])
         
         
-        self.mapWindow.HighlightCategory(cats)
+        self.mapWindow.HighlightCategory(sel_cats)
         if event:
         if event:
             event.Skip()
             event.Skip()
         
         
@@ -388,7 +401,7 @@ class CategoryListCtrl(wx.ListCtrl,
     
     
     def OnZoomToAreasByCat(self, event):
     def OnZoomToAreasByCat(self, event):
         """!Zoom to areas of given category"""
         """!Zoom to areas of given category"""
-        cat = self.statisticsList[self.rightClickedItemIdx]
+        cat = self.stats_data.GetCategories()[self.rightClickedItemIdx]
         self.mapWindow.ZoomToAreasByCat(cat)
         self.mapWindow.ZoomToAreasByCat(cat)
         
         
     def DeselectAll(self):
     def DeselectAll(self):
@@ -401,8 +414,9 @@ class CategoryListCtrl(wx.ListCtrl,
         self.OnCategorySelected(None)
         self.OnCategorySelected(None)
         
         
     def OnGetItemText(self, item, col):
     def OnGetItemText(self, item, col):
-        cat = self.statisticsList[item]
-        return getattr(self.statisticsDict[cat], self.columns[col][1]) 
+        cat = self.stats_data.GetCategories()[item]
+        stat = self.stats_data.GetStatistics(cat)
+        return getattr(stat, self.columns[col][1]) 
 
 
     def OnGetItemImage(self, item):
     def OnGetItemImage(self, item):
         return -1
         return -1

+ 31 - 28
gui/wxpython/iclass/frame.py

@@ -57,12 +57,12 @@ import grass.script as grass
 from iclass.digit       import IClassVDigitWindow, IClassVDigit
 from iclass.digit       import IClassVDigitWindow, IClassVDigit
 from iclass.toolbars    import IClassMapToolbar, IClassMiscToolbar,\
 from iclass.toolbars    import IClassMapToolbar, IClassMiscToolbar,\
                                IClassToolbar, IClassMapManagerToolbar
                                IClassToolbar, IClassMapManagerToolbar
-from iclass.statistics  import Statistics, BandStatistics
+from iclass.statistics  import StatisticsData, Statistics, BandStatistics
 from iclass.dialogs     import CategoryListCtrl, IClassCategoryManagerDialog,\
 from iclass.dialogs     import CategoryListCtrl, IClassCategoryManagerDialog,\
                                IClassGroupDialog, IClassSignatureFileDialog,\
                                IClassGroupDialog, IClassSignatureFileDialog,\
                                IClassExportAreasDialog, IClassMapDialog
                                IClassExportAreasDialog, IClassMapDialog
 from iclass.plots       import PlotPanel
 from iclass.plots       import PlotPanel
-        
+
 class IClassMapFrame(DoubleMapFrame):
 class IClassMapFrame(DoubleMapFrame):
     """! wxIClass main frame
     """! wxIClass main frame
     
     
@@ -158,13 +158,13 @@ class IClassMapFrame(DoubleMapFrame):
         # dialogs
         # dialogs
         self.dialogs = dict()
         self.dialogs = dict()
         self.dialogs['classManager'] = None
         self.dialogs['classManager'] = None
+        self.dialogs['scatt_plot'] = None
         # just to make digitizer happy
         # just to make digitizer happy
         self.dialogs['attributes'] = None
         self.dialogs['attributes'] = None
         self.dialogs['category']   = None
         self.dialogs['category']   = None
         
         
         # PyPlot init
         # PyPlot init
-        self.plotPanel = PlotPanel(self, statDict = self.statisticsDict,
-                                   statList = self.statisticsList)
+        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
                                    
                                    
         self._addPanes()
         self._addPanes()
         self._mgr.Update()
         self._mgr.Update()
@@ -193,8 +193,8 @@ class IClassMapFrame(DoubleMapFrame):
             I_iclass_free_statistics(st)
             I_iclass_free_statistics(st)
             
             
         self.RemoveTempVector()
         self.RemoveTempVector()
-        for i in self.statisticsList:
-            self.RemoveTempRaster(self.statisticsDict[i].rasterName)
+        for i in self.stats_data.GetCategories():
+            self.RemoveTempRaster(self.stats_data.GetStatistics(i).rasterName)
             
             
     def OnHelp(self, event):
     def OnHelp(self, event):
         """!Show help page"""
         """!Show help page"""
@@ -396,8 +396,8 @@ class IClassMapFrame(DoubleMapFrame):
         
         
         @return 'R:G:B'
         @return 'R:G:B'
         """
         """
-        if cat in self.statisticsDict:
-            return self.statisticsDict[cat].color
+        if cat in self.stats_data.GetCategories():
+            return self.stats_data.GetStatistics(cat).color
         return '0:0:0'
         return '0:0:0'
         
         
     def OnZoomMenu(self, event):
     def OnZoomMenu(self, event):
@@ -474,7 +474,7 @@ class IClassMapFrame(DoubleMapFrame):
     def OnImportAreas(self, event):
     def OnImportAreas(self, event):
         """!Import training areas"""
         """!Import training areas"""
         # check if we have any changes
         # check if we have any changes
-        if self.GetAreasCount() or self.statisticsList:
+        if self.GetAreasCount() or self.stats_data.GetCategories():
             qdlg = wx.MessageDialog(parent = self,
             qdlg = wx.MessageDialog(parent = self,
                                     message = _("All changes will be lost. "
                                     message = _("All changes will be lost. "
                                                 "Do you want to continue?") ,
                                                 "Do you want to continue?") ,
@@ -558,12 +558,11 @@ class IClassMapFrame(DoubleMapFrame):
         self.poMapInfo = self.GetFirstWindow().digit.GetDisplay().poMapInfo
         self.poMapInfo = self.GetFirstWindow().digit.GetDisplay().poMapInfo
         
         
         # remove temporary rasters
         # remove temporary rasters
-        for i in self.statisticsList:
-            self.RemoveTempRaster(self.statisticsDict[i].rasterName)
+        for cat in self.stats_data.GetCategories():
+            self.RemoveTempRaster(self.stats_data.GetStatistics(cat).rasterName)
         
         
         # clear current statistics
         # clear current statistics
-        self.statisticsDict.clear()
-        del self.statisticsList[:] # not ...=[] !
+        self.stats_data.DeleteAllStatistics()
         
         
         # reset plots
         # reset plots
         self.plotPanel.Reset()
         self.plotPanel.Reset()
@@ -658,7 +657,7 @@ class IClassMapFrame(DoubleMapFrame):
             
             
             if self.ExportAreas(vectorName = vName, withTable = withTable):
             if self.ExportAreas(vectorName = vName, withTable = withTable):
                 GMessage(_("%d training areas (%d classes) exported to vector map <%s>.") % \
                 GMessage(_("%d training areas (%d classes) exported to vector map <%s>.") % \
-                             (self.GetAreasCount(), len(self.statisticsList),
+                             (self.GetAreasCount(), len(self.stats_data.GetCategories()),
                               self.exportVector), parent = self)
                               self.exportVector), parent = self)
                     
                     
     def ExportAreas(self, vectorName, withTable):
     def ExportAreas(self, vectorName, withTable):
@@ -716,8 +715,8 @@ class IClassMapFrame(DoubleMapFrame):
             return False
             return False
         
         
         # populate table
         # populate table
-        for cat in self.statisticsList:
-            stat = self.statisticsDict[cat]
+        for cat in self.stats_data.GetCategories():
+            stat = self.stats_data.GetStatistics(cat)
             
             
             self._runDBUpdate(map = vectorName, column = "class", value = stat.name, cat = cat)
             self._runDBUpdate(map = vectorName, column = "class", value = stat.name, cat = cat)
             self._runDBUpdate(map = vectorName, column = "color", value = stat.color, cat = cat)
             self._runDBUpdate(map = vectorName, column = "color", value = stat.color, cat = cat)
@@ -769,13 +768,14 @@ class IClassMapFrame(DoubleMapFrame):
         
         
         Updates number of stddev, histograms, layer in preview display. 
         Updates number of stddev, histograms, layer in preview display. 
         """
         """
-        nstd = self.statisticsDict[currentCat].nstd
+        stat = self.stats_data.GetStatistics(currentCat)
+        nstd = stat.nstd
         self.toolbars['iClass'].UpdateStddev(nstd)
         self.toolbars['iClass'].UpdateStddev(nstd)
         
         
         self.plotPanel.UpdateCategory(currentCat)
         self.plotPanel.UpdateCategory(currentCat)
         self.plotPanel.OnPlotTypeSelected(None)
         self.plotPanel.OnPlotTypeSelected(None)
                                    
                                    
-        name = self.statisticsDict[currentCat].rasterName
+        name = stat.rasterName
         name = self.previewMapManager.GetAlias(name)
         name = self.previewMapManager.GetAlias(name)
         if name:
         if name:
             self.previewMapManager.SelectLayer(name)
             self.previewMapManager.SelectLayer(name)
@@ -804,12 +804,12 @@ class IClassMapFrame(DoubleMapFrame):
         
         
     def UpdateRasterName(self, newName, cat):
     def UpdateRasterName(self, newName, cat):
         """!Update alias of raster map when category name is changed"""
         """!Update alias of raster map when category name is changed"""
-        origName = self.statisticsDict[cat].rasterName
+        origName = self.stats_data.GetStatistics(cat).rasterName
         self.previewMapManager.SetAlias(origName, newName)
         self.previewMapManager.SetAlias(origName, newName)
         
         
     def StddevChanged(self, cat, nstd):
     def StddevChanged(self, cat, nstd):
         """!Standard deviation multiplier changed, rerender map, histograms"""
         """!Standard deviation multiplier changed, rerender map, histograms"""
-        stat = self.statisticsDict[cat]
+        stat = self.stats_data.GetStatistics(cat)
         stat.nstd = nstd
         stat.nstd = nstd
         
         
         if not stat.IsReady():
         if not stat.IsReady():
@@ -867,8 +867,7 @@ class IClassMapFrame(DoubleMapFrame):
         if self.RunAnalysis():
         if self.RunAnalysis():
             currentCat = self.GetCurrentCategoryIdx()
             currentCat = self.GetCurrentCategoryIdx()
             self.plotPanel.UpdatePlots(group = self.group, currentCat = currentCat,
             self.plotPanel.UpdatePlots(group = self.group, currentCat = currentCat,
-                                       statDict = self.statisticsDict,
-                                       statList = self.statisticsList)
+                                       stats_data = self.stats_data)
         
         
     def RunAnalysis(self):
     def RunAnalysis(self):
         """!Run analysis
         """!Run analysis
@@ -893,9 +892,12 @@ class IClassMapFrame(DoubleMapFrame):
         I_free_signatures(self.signatures)
         I_free_signatures(self.signatures)
         I_iclass_init_signatures(self.signatures, self.refer)
         I_iclass_init_signatures(self.signatures, self.refer)
         
         
-        cats = self.statisticsList[:]
+        # why create copy
+        #cats = self.statisticsList[:]
+        
+        cats = self.stats_data.GetCategories()
         for i in cats:
         for i in cats:
-            stats = self.statisticsDict[i]
+            stats = self.stats_data.GetStatistics(i)
             
             
             statistics_obj = IClass_statistics()
             statistics_obj = IClass_statistics()
             statistics = pointer(statistics_obj)
             statistics = pointer(statistics_obj)
@@ -912,9 +914,11 @@ class IClassMapFrame(DoubleMapFrame):
                 # tests
                 # tests
                 self.cStatisticsDict[i] = statistics
                 self.cStatisticsDict[i] = statistics
                 
                 
-                stats.SetStatistics(statistics)
+                stats.SetFromcStatistics(statistics)
                 stats.SetReady()
                 stats.SetReady()
-                self.statisticsDict[stats.category] = stats
+                
+                # stat is already part of stats_data?
+                #self.statisticsDict[stats.category] = stats
                 
                 
                 self.ConvertToNull(name = stats.rasterName)
                 self.ConvertToNull(name = stats.rasterName)
                 self.previewMapManager.AddLayer(name = stats.rasterName,
                 self.previewMapManager.AddLayer(name = stats.rasterName,
@@ -977,8 +981,7 @@ class IClassMapFrame(DoubleMapFrame):
         self.group = None
         self.group = None
         self.sigFile = None
         self.sigFile = None
         
         
-        self.statisticsDict = {}
-        self.statisticsList = []
+        self.stats_data = StatisticsData()
         
         
         self.cStatisticsDict = {}
         self.cStatisticsDict = {}
         
         

+ 20 - 17
gui/wxpython/iclass/plots.py

@@ -28,15 +28,14 @@ class PlotPanel(scrolled.ScrolledPanel):
     for each band and for one category. Coincidence plots show min max range
     for each band and for one category. Coincidence plots show min max range
     of classes for each band.
     of classes for each band.
     """
     """
-    def __init__(self, parent, statDict, statList):
+    def __init__(self, parent, stats_data):
         scrolled.ScrolledPanel.__init__(self, parent)
         scrolled.ScrolledPanel.__init__(self, parent)
         
         
         self.SetupScrolling(scroll_x = False, scroll_y = True)
         self.SetupScrolling(scroll_x = False, scroll_y = True)
         self.parent = parent
         self.parent = parent
         self.canvasList = []
         self.canvasList = []
         self.bandList = []
         self.bandList = []
-        self.statDict = statDict
-        self.statList = statList
+        self.stats_data = stats_data
         self.currentCat = None
         self.currentCat = None
         
         
         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
@@ -60,17 +59,19 @@ class PlotPanel(scrolled.ScrolledPanel):
             return
             return
         
         
         if self.plotSwitch.GetSelection() == 0:
         if self.plotSwitch.GetSelection() == 0:
-            if not self.statDict[self.currentCat].IsReady():
+            stat = self.stats_data.GetStatistics(self.currentCat)
+            if not stat.IsReady():
                 self.ClearPlots()
                 self.ClearPlots()
                 return
                 return
-            self.DrawHistograms(self.statDict[self.currentCat])
+            self.DrawHistograms(stat)
         else:
         else:
             self.DrawCoincidencePlots()
             self.DrawCoincidencePlots()
             
             
     def StddevChanged(self):
     def StddevChanged(self):
         """!Standard deviation multiplier changed, redraw histograms"""
         """!Standard deviation multiplier changed, redraw histograms"""
         if self.plotSwitch.GetSelection() == 0:
         if self.plotSwitch.GetSelection() == 0:
-            self.UpdateRanges(self.statDict[self.currentCat])
+            stat = self.stats_data.GetStatistics(self.currentCat)
+            self.UpdateRanges(stat)
         
         
     def EnableZoom(self, type, enable = True):
     def EnableZoom(self, type, enable = True):
         for canvas in self.canvasList:
         for canvas in self.canvasList:
@@ -114,22 +115,21 @@ class PlotPanel(scrolled.ScrolledPanel):
         self.SetVirtualSize(self.GetBestVirtualSize()) 
         self.SetVirtualSize(self.GetBestVirtualSize()) 
         self.Layout()
         self.Layout()
         
         
-    def UpdatePlots(self, group, currentCat, statDict, statList):
+    def UpdatePlots(self, group, currentCat, stats_data):
         """!Update plots after new analysis
         """!Update plots after new analysis
         
         
         @param group imagery group
         @param group imagery group
         @param currentCat currently selected category (class)
         @param currentCat currently selected category (class)
-        @param statDict dictionary with Statistics
-        @param statList list of currently used categories
+        @param stats_data StatisticsData instance (defined in statistics.py)
         """
         """
-        self.statDict = statDict
-        self.statList = statList
+        self.stats_data = stats_data
         self.currentCat = currentCat
         self.currentCat = currentCat
         self.bandList = self.parent.GetGroupLayers(group)
         self.bandList = self.parent.GetGroupLayers(group)
         
         
         graphType = self.plotSwitch.GetSelection()
         graphType = self.plotSwitch.GetSelection()
-        
-        if not statDict[currentCat].IsReady() and graphType == 0:
+
+        stat = self.stats_data.GetStatistics(currentCat)
+        if not stat.IsReady() and graphType == 0:
             return
             return
             
             
         self.DestroyPlots()
         self.DestroyPlots()
@@ -146,12 +146,15 @@ class PlotPanel(scrolled.ScrolledPanel):
             lines = []
             lines = []
             level = 0.5
             level = 0.5
             lines.append(self.DrawInvisibleLine(level))
             lines.append(self.DrawInvisibleLine(level))
-            for i, cat in enumerate(self.statList):
-                if not self.statDict[cat].IsReady():
+
+            cats = self.stats_data.GetCategories()
+            for i, cat in enumerate(cats):
+                stat = self.stats_data.GetStatistics(cat)
+                if not stat.IsReady():
                     continue
                     continue
-                color = self.statDict[cat].color
+                color = stat.color
                 level = i + 1
                 level = i + 1
-                line = self.DrawCoincidenceLine(level, color, self.statDict[cat].bands[bandIdx])
+                line = self.DrawCoincidenceLine(level, color, stat.bands[bandIdx])
                 lines.append(line)
                 lines.append(line)
             
             
             # invisible 
             # invisible 

+ 80 - 18
gui/wxpython/iclass/statistics.py

@@ -4,10 +4,11 @@
 @brief wxIClass classes for storing statistics about cells in training areas.
 @brief wxIClass classes for storing statistics about cells in training areas.
 
 
 Classes:
 Classes:
+ - statistics::StatisticsData
  - statistics::Statistics
  - statistics::Statistics
  - statistics::BandStatistics
  - statistics::BandStatistics
 
 
-(C) 2006-2011 by the GRASS Development Team
+(C) 2006-2011, 2013 by the GRASS Development Team
 This program is free software under the GNU General Public
 This program is free software under the GNU General Public
 License (>=v2). Read the file COPYING that comes with GRASS
 License (>=v2). Read the file COPYING that comes with GRASS
 for details.
 for details.
@@ -27,6 +28,50 @@ try:
 except ImportError, e:
 except ImportError, e:
     sys.stderr.write(_("Loading imagery lib failed"))
     sys.stderr.write(_("Loading imagery lib failed"))
 
 
+from grass.pydispatch.signal import Signal
+
+class StatisticsData:
+    """!Stores all statistics.
+    """ 
+    def __init__(self):
+        self.statisticsDict = {}
+        self.statisticsList = []
+
+        self.statisticsAdded = Signal("StatisticsData.statisticsAdded") 
+        self.statisticsDeleted = Signal("StatisticsData.statisticsDeleted") 
+        self.allStatisticsDeleted = Signal("StatisticsData.allStatisticsDeleted") 
+
+        self.statisticsSet = Signal("StatisticsData.statisticsSet") 
+
+    def GetStatistics(self, cat):
+        return self.statisticsDict[cat]
+
+    def AddStatistics(self, cat, name, color):
+        st = Statistics()
+        st.SetBaseStatistics(cat = cat, name = name, color = color)
+        st.statisticsSet.connect(lambda stats : self.statisticsSet.emit(cat = cat, 
+                                                                        stats = stats))
+
+        self.statisticsDict[cat] = st
+        self.statisticsList.append(cat)
+
+        self.statisticsAdded.emit(cat = cat, name = name, color = color)
+
+    def DeleteStatistics(self, cat):
+        del self.statisticsDict[cat]
+        self.statisticsList.remove(cat)
+
+        self.statisticsDeleted.emit(cat = cat)
+
+    def GetCategories(self):
+        return self.statisticsList[:]
+
+    def DeleteAllStatistics(self):
+        self.statisticsDict.clear()
+        del self.statisticsList[:]  # not ...=[] !
+
+        self.allStatisticsDeleted.emit()
+
 class Statistics:
 class Statistics:
     """! Statistis conected to one class (category).
     """! Statistis conected to one class (category).
     
     
@@ -44,8 +89,9 @@ class Statistics:
         self.nstd = 1.5
         self.nstd = 1.5
         self.bands = []
         self.bands = []
         self.ready = False
         self.ready = False
-        
-        
+
+        self.statisticsSet = Signal("Statistics.statisticsSet") 
+
     def SetReady(self, ready = True):
     def SetReady(self, ready = True):
         self.ready = ready
         self.ready = ready
         
         
@@ -68,7 +114,7 @@ class Statistics:
         name = name.replace(' ', '_')
         name = name.replace(' ', '_')
         self.rasterName = name + '_' + os.path.basename(rasterPath)
         self.rasterName = name + '_' + os.path.basename(rasterPath)
         
         
-    def SetStatistics(self, cStatistics):
+    def SetFromcStatistics(self, cStatistics):
         """! Sets all statistical values.
         """! Sets all statistical values.
         
         
         Copies all statistic values from \a cStattistics.
         Copies all statistic values from \a cStattistics.
@@ -76,31 +122,40 @@ class Statistics:
         @param cStatistics pointer to C statistics structure
         @param cStatistics pointer to C statistics structure
         """
         """
         cat = c_int()
         cat = c_int()
+
+        set_stats = {}
         I_iclass_statistics_get_cat(cStatistics, byref(cat))
         I_iclass_statistics_get_cat(cStatistics, byref(cat))
-        self.category = cat.value
-        
+        if self.category != cat.value:
+            set_stats["category"] = cat.value
+
         name = c_char_p()
         name = c_char_p()
         I_iclass_statistics_get_name(cStatistics, byref(name))
         I_iclass_statistics_get_name(cStatistics, byref(name))
-        self.name = name.value
-        
+        if self.name != name.value:
+            set_stats["name"] = name.value
+
         color = c_char_p()
         color = c_char_p()
         I_iclass_statistics_get_color(cStatistics, byref(color))
         I_iclass_statistics_get_color(cStatistics, byref(color))
-        self.color = color.value
+        if self.color != color.value:
+            set_stats["color"] = color.value
         
         
         nbands = c_int()
         nbands = c_int()
         I_iclass_statistics_get_nbands(cStatistics, byref(nbands))
         I_iclass_statistics_get_nbands(cStatistics, byref(nbands))
-        self.nbands = nbands.value
+        if self.nbands != nbands.value:
+            set_stats["nbands"] = nbands.value
         
         
         ncells = c_int()
         ncells = c_int()
         I_iclass_statistics_get_ncells(cStatistics, byref(ncells))
         I_iclass_statistics_get_ncells(cStatistics, byref(ncells))
-        self.ncells = ncells.value
-        
+        if self.ncells != ncells.value:
+            set_stats["ncells"] = ncells.value
+
         nstd = c_float()
         nstd = c_float()
         I_iclass_statistics_get_nstd(cStatistics, byref(nstd))
         I_iclass_statistics_get_nstd(cStatistics, byref(nstd))
-        self.nstd = nstd.value
-        
+        if self.nstd != nstd.value:
+            set_stats["nstd"] = nstd.value
+                
+        self.SetStatistics(set_stats)
         self.SetBandStatistics(cStatistics)
         self.SetBandStatistics(cStatistics)
-        
+
     def SetBandStatistics(self, cStatistics):
     def SetBandStatistics(self, cStatistics):
         """! Sets all band statistics.
         """! Sets all band statistics.
         
         
@@ -109,9 +164,16 @@ class Statistics:
         self.bands = []
         self.bands = []
         for i in range(self.nbands):
         for i in range(self.nbands):
             band = BandStatistics()
             band = BandStatistics()
-            band.SetStatistics(cStatistics, index = i)
+            band.SetFromcStatistics(cStatistics, index = i)
             self.bands.append(band)
             self.bands.append(band)
-        
+
+    def SetStatistics(self, stats):
+
+        for st, val in stats.iteritems():
+            setattr(self, st, val)
+
+        self.statisticsSet.emit(stats = stats)
+
 class BandStatistics:
 class BandStatistics:
     """! Statistis conected to one band within class (category).
     """! Statistis conected to one band within class (category).
     
     
@@ -125,7 +187,7 @@ class BandStatistics:
         self.histo = [0] * 256 # max categories
         self.histo = [0] * 256 # max categories
         
         
         
         
-    def SetStatistics(self, cStatistics, index):
+    def SetFromcStatistics(self, cStatistics, index):
         """! Sets statistics for one band by given index.
         """! Sets statistics for one band by given index.
         
         
         @param cStatistics pointer to C statistics structure
         @param cStatistics pointer to C statistics structure