[GRASS-SVN] r57284 - grass/trunk/gui/wxpython/iclass

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Jul 26 17:04:35 PDT 2013


Author: turek
Date: 2013-07-26 17:04:35 -0700 (Fri, 26 Jul 2013)
New Revision: 57284

Modified:
   grass/trunk/gui/wxpython/iclass/dialogs.py
   grass/trunk/gui/wxpython/iclass/frame.py
   grass/trunk/gui/wxpython/iclass/plots.py
   grass/trunk/gui/wxpython/iclass/statistics.py
Log:
wx.iclass: added interface for statistics data

Modified: grass/trunk/gui/wxpython/iclass/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/iclass/dialogs.py	2013-07-26 18:18:10 UTC (rev 57283)
+++ grass/trunk/gui/wxpython/iclass/dialogs.py	2013-07-27 00:04:35 UTC (rev 57284)
@@ -154,8 +154,8 @@
                            label = " %s " % _("Classes"))
         sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
         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)
         deleteButton = wx.Button(panel, id = wx.ID_DELETE)
         
@@ -187,8 +187,8 @@
         self.Layout()
 
     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:
             cat = 1
         defaultName = 'class' + '_' + str(cat) # intentionally not translatable
@@ -221,16 +221,13 @@
     when deleting class (category).
     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
     """
-    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 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
         """
         wx.ListCtrl.__init__(self, parent, id,
@@ -239,9 +236,8 @@
                         (_('Color'), 'color'))
         self.Populate(columns = self.columns)
         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
         
@@ -254,7 +250,15 @@
         
         self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnClassRightUp) #wxMSW
         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):
         attr = self.columns[column][1]
         if attr == 'name':
@@ -263,7 +267,10 @@
             except UnicodeEncodeError:
                 GMessage(parent = self, message = _("Please use only ASCII characters."))
                 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()
         toolbar = self.mapWindow.toolbars['iClass']
@@ -284,41 +291,46 @@
         
     def AddCategory(self, cat, name, color):
         """!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.mapWindow.UpdateChangeState(changes = True)
                 
     def DeleteCategory(self):
         indexList = sorted(self.GetSelectedIndices(), reverse = True)
-        cats = []
+        del_cats = []
+        cats = self.stats_data.GetCategories()
+
         for i in indexList:
             # 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)
             
-            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.mapWindow.UpdateChangeState(changes = True)
         
-        self.mapWindow.DeleteAreas(cats = cats)
+        self.mapWindow.DeleteAreas(cats = del_cats)
     
     def UpdateChoice(self):
         toolbar = self.mapWindow.toolbars['iClass']
         name = toolbar.GetSelectedCategoryName()
         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:
             toolbar.choice.SetStringSelection(name)
         elif catNames:
@@ -361,11 +373,12 @@
     def OnCategorySelected(self, event):
         """!Highlight selected areas"""
         indexList = self.GetSelectedIndices()
-        cats = []
+        sel_cats = []
+        cats = self.stats_data.GetCategories()
         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:
             event.Skip()
         
@@ -388,7 +401,7 @@
     
     def OnZoomToAreasByCat(self, event):
         """!Zoom to areas of given category"""
-        cat = self.statisticsList[self.rightClickedItemIdx]
+        cat = self.stats_data.GetCategories()[self.rightClickedItemIdx]
         self.mapWindow.ZoomToAreasByCat(cat)
         
     def DeselectAll(self):
@@ -401,8 +414,9 @@
         self.OnCategorySelected(None)
         
     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):
         return -1

Modified: grass/trunk/gui/wxpython/iclass/frame.py
===================================================================
--- grass/trunk/gui/wxpython/iclass/frame.py	2013-07-26 18:18:10 UTC (rev 57283)
+++ grass/trunk/gui/wxpython/iclass/frame.py	2013-07-27 00:04:35 UTC (rev 57284)
@@ -57,12 +57,12 @@
 from iclass.digit       import IClassVDigitWindow, IClassVDigit
 from iclass.toolbars    import IClassMapToolbar, IClassMiscToolbar,\
                                IClassToolbar, IClassMapManagerToolbar
-from iclass.statistics  import Statistics, BandStatistics
+from iclass.statistics  import StatisticsData, Statistics, BandStatistics
 from iclass.dialogs     import CategoryListCtrl, IClassCategoryManagerDialog,\
                                IClassGroupDialog, IClassSignatureFileDialog,\
                                IClassExportAreasDialog, IClassMapDialog
 from iclass.plots       import PlotPanel
-        
+
 class IClassMapFrame(DoubleMapFrame):
     """! wxIClass main frame
     
@@ -158,13 +158,13 @@
         # dialogs
         self.dialogs = dict()
         self.dialogs['classManager'] = None
+        self.dialogs['scatt_plot'] = None
         # just to make digitizer happy
         self.dialogs['attributes'] = None
         self.dialogs['category']   = None
         
         # PyPlot init
-        self.plotPanel = PlotPanel(self, statDict = self.statisticsDict,
-                                   statList = self.statisticsList)
+        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
                                    
         self._addPanes()
         self._mgr.Update()
@@ -193,8 +193,8 @@
             I_iclass_free_statistics(st)
             
         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):
         """!Show help page"""
@@ -396,8 +396,8 @@
         
         @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'
         
     def OnZoomMenu(self, event):
@@ -474,7 +474,7 @@
     def OnImportAreas(self, event):
         """!Import training areas"""
         # 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,
                                     message = _("All changes will be lost. "
                                                 "Do you want to continue?") ,
@@ -558,12 +558,11 @@
         self.poMapInfo = self.GetFirstWindow().digit.GetDisplay().poMapInfo
         
         # 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
-        self.statisticsDict.clear()
-        del self.statisticsList[:] # not ...=[] !
+        self.stats_data.DeleteAllStatistics()
         
         # reset plots
         self.plotPanel.Reset()
@@ -658,7 +657,7 @@
             
             if self.ExportAreas(vectorName = vName, withTable = withTable):
                 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)
                     
     def ExportAreas(self, vectorName, withTable):
@@ -716,8 +715,8 @@
             return False
         
         # 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 = "color", value = stat.color, cat = cat)
@@ -769,13 +768,14 @@
         
         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.plotPanel.UpdateCategory(currentCat)
         self.plotPanel.OnPlotTypeSelected(None)
                                    
-        name = self.statisticsDict[currentCat].rasterName
+        name = stat.rasterName
         name = self.previewMapManager.GetAlias(name)
         if name:
             self.previewMapManager.SelectLayer(name)
@@ -804,12 +804,12 @@
         
     def UpdateRasterName(self, newName, cat):
         """!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)
         
     def StddevChanged(self, cat, nstd):
         """!Standard deviation multiplier changed, rerender map, histograms"""
-        stat = self.statisticsDict[cat]
+        stat = self.stats_data.GetStatistics(cat)
         stat.nstd = nstd
         
         if not stat.IsReady():
@@ -867,8 +867,7 @@
         if self.RunAnalysis():
             currentCat = self.GetCurrentCategoryIdx()
             self.plotPanel.UpdatePlots(group = self.group, currentCat = currentCat,
-                                       statDict = self.statisticsDict,
-                                       statList = self.statisticsList)
+                                       stats_data = self.stats_data)
         
     def RunAnalysis(self):
         """!Run analysis
@@ -893,9 +892,12 @@
         I_free_signatures(self.signatures)
         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:
-            stats = self.statisticsDict[i]
+            stats = self.stats_data.GetStatistics(i)
             
             statistics_obj = IClass_statistics()
             statistics = pointer(statistics_obj)
@@ -912,10 +914,12 @@
                 # tests
                 self.cStatisticsDict[i] = statistics
                 
-                stats.SetStatistics(statistics)
+                stats.SetFromcStatistics(statistics)
                 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.previewMapManager.AddLayer(name = stats.rasterName,
                                                 alias = stats.name, resultsLayer = True)
@@ -977,8 +981,7 @@
         self.group = None
         self.sigFile = None
         
-        self.statisticsDict = {}
-        self.statisticsList = []
+        self.stats_data = StatisticsData()
         
         self.cStatisticsDict = {}
         

Modified: grass/trunk/gui/wxpython/iclass/plots.py
===================================================================
--- grass/trunk/gui/wxpython/iclass/plots.py	2013-07-26 18:18:10 UTC (rev 57283)
+++ grass/trunk/gui/wxpython/iclass/plots.py	2013-07-27 00:04:35 UTC (rev 57284)
@@ -28,15 +28,14 @@
     for each band and for one category. Coincidence plots show min max range
     of classes for each band.
     """
-    def __init__(self, parent, statDict, statList):
+    def __init__(self, parent, stats_data):
         scrolled.ScrolledPanel.__init__(self, parent)
         
         self.SetupScrolling(scroll_x = False, scroll_y = True)
         self.parent = parent
         self.canvasList = []
         self.bandList = []
-        self.statDict = statDict
-        self.statList = statList
+        self.stats_data = stats_data
         self.currentCat = None
         
         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
@@ -60,17 +59,19 @@
             return
         
         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()
                 return
-            self.DrawHistograms(self.statDict[self.currentCat])
+            self.DrawHistograms(stat)
         else:
             self.DrawCoincidencePlots()
             
     def StddevChanged(self):
         """!Standard deviation multiplier changed, redraw histograms"""
         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):
         for canvas in self.canvasList:
@@ -114,22 +115,21 @@
         self.SetVirtualSize(self.GetBestVirtualSize()) 
         self.Layout()
         
-    def UpdatePlots(self, group, currentCat, statDict, statList):
+    def UpdatePlots(self, group, currentCat, stats_data):
         """!Update plots after new analysis
         
         @param group imagery group
         @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.bandList = self.parent.GetGroupLayers(group)
         
         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
             
         self.DestroyPlots()
@@ -146,12 +146,15 @@
             lines = []
             level = 0.5
             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
-                color = self.statDict[cat].color
+                color = stat.color
                 level = i + 1
-                line = self.DrawCoincidenceLine(level, color, self.statDict[cat].bands[bandIdx])
+                line = self.DrawCoincidenceLine(level, color, stat.bands[bandIdx])
                 lines.append(line)
             
             # invisible 

Modified: grass/trunk/gui/wxpython/iclass/statistics.py
===================================================================
--- grass/trunk/gui/wxpython/iclass/statistics.py	2013-07-26 18:18:10 UTC (rev 57283)
+++ grass/trunk/gui/wxpython/iclass/statistics.py	2013-07-27 00:04:35 UTC (rev 57284)
@@ -4,10 +4,11 @@
 @brief wxIClass classes for storing statistics about cells in training areas.
 
 Classes:
+ - statistics::StatisticsData
  - statistics::Statistics
  - 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
 License (>=v2). Read the file COPYING that comes with GRASS
 for details.
@@ -27,6 +28,50 @@
 except ImportError, e:
     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:
     """! Statistis conected to one class (category).
     
@@ -44,8 +89,9 @@
         self.nstd = 1.5
         self.bands = []
         self.ready = False
-        
-        
+
+        self.statisticsSet = Signal("Statistics.statisticsSet") 
+
     def SetReady(self, ready = True):
         self.ready = ready
         
@@ -68,7 +114,7 @@
         name = name.replace(' ', '_')
         self.rasterName = name + '_' + os.path.basename(rasterPath)
         
-    def SetStatistics(self, cStatistics):
+    def SetFromcStatistics(self, cStatistics):
         """! Sets all statistical values.
         
         Copies all statistic values from \a cStattistics.
@@ -76,31 +122,40 @@
         @param cStatistics pointer to C statistics structure
         """
         cat = c_int()
+
+        set_stats = {}
         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()
         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()
         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()
         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()
         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()
         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)
-        
+
     def SetBandStatistics(self, cStatistics):
         """! Sets all band statistics.
         
@@ -109,9 +164,16 @@
         self.bands = []
         for i in range(self.nbands):
             band = BandStatistics()
-            band.SetStatistics(cStatistics, index = i)
+            band.SetFromcStatistics(cStatistics, index = i)
             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:
     """! Statistis conected to one band within class (category).
     
@@ -125,7 +187,7 @@
         self.histo = [0] * 256 # max categories
         
         
-    def SetStatistics(self, cStatistics, index):
+    def SetFromcStatistics(self, cStatistics, index):
         """! Sets statistics for one band by given index.
         
         @param cStatistics pointer to C statistics structure



More information about the grass-commit mailing list