|
@@ -35,6 +35,7 @@ import locale
|
|
import tempfile
|
|
import tempfile
|
|
import copy
|
|
import copy
|
|
import types
|
|
import types
|
|
|
|
+import math
|
|
|
|
|
|
from core import globalvar
|
|
from core import globalvar
|
|
import wx
|
|
import wx
|
|
@@ -399,68 +400,66 @@ class VirtualAttributeList(wx.ListCtrl,
|
|
|
|
|
|
popupMenu = wx.Menu()
|
|
popupMenu = wx.Menu()
|
|
|
|
|
|
- if not hasattr (self, "popupID1"):
|
|
|
|
- #TODO put to dict
|
|
|
|
- self.popupID1 = wx.NewId()
|
|
|
|
- self.popupID2 = wx.NewId()
|
|
|
|
- self.popupID3 = wx.NewId()
|
|
|
|
- self.popupID4 = wx.NewId()
|
|
|
|
- self.popupID5 = wx.NewId()
|
|
|
|
- self.popupID6 = wx.NewId()
|
|
|
|
- self.popupID7 = wx.NewId()
|
|
|
|
- self.popupID8 = wx.NewId()
|
|
|
|
- self.popupID9 = wx.NewId()
|
|
|
|
- self.popupID10 = wx.NewId()
|
|
|
|
- self.popupID11 = wx.NewId()
|
|
|
|
- self.popupID12 = wx.NewId()
|
|
|
|
- self.popupID13 = wx.NewId()
|
|
|
|
- self.popupID14 = wx.NewId()
|
|
|
|
-
|
|
|
|
- popupMenu.Append(self.popupID1, text = _("Sort ascending"))
|
|
|
|
- popupMenu.Append(self.popupID2, text = _("Sort descending"))
|
|
|
|
|
|
+ if not hasattr (self, "popupID"):
|
|
|
|
+ self.popupId = { 'sortAsc' : wx.NewId(),
|
|
|
|
+ 'sortDesc' : wx.NewId(),
|
|
|
|
+ 'calculate' : wx.NewId(),
|
|
|
|
+ 'area' : wx.NewId(),
|
|
|
|
+ 'length' : wx.NewId(),
|
|
|
|
+ 'compact' : wx.NewId(),
|
|
|
|
+ 'fractal' : wx.NewId(),
|
|
|
|
+ 'perimeter' : wx.NewId(),
|
|
|
|
+ 'ncats' : wx.NewId(),
|
|
|
|
+ 'slope' : wx.NewId(),
|
|
|
|
+ 'lsin' : wx.NewId(),
|
|
|
|
+ 'lazimuth' : wx.NewId(),
|
|
|
|
+ 'calculator' : wx.NewId(),
|
|
|
|
+ 'stats' : wx.NewId() }
|
|
|
|
+
|
|
|
|
+ popupMenu.Append(self.popupId['sortAsc'], text = _("Sort ascending"))
|
|
|
|
+ popupMenu.Append(self.popupId['sortDesc'], text = _("Sort descending"))
|
|
popupMenu.AppendSeparator()
|
|
popupMenu.AppendSeparator()
|
|
subMenu = wx.Menu()
|
|
subMenu = wx.Menu()
|
|
- popupMenu.AppendMenu(self.popupID3, _("Calculate (only numeric columns)"),
|
|
|
|
|
|
+ popupMenu.AppendMenu(self.popupId['calculate'], _("Calculate (only numeric columns)"),
|
|
subMenu)
|
|
subMenu)
|
|
- popupMenu.Append(self.popupID13, text = _("Field calculator"))
|
|
|
|
|
|
+ popupMenu.Append(self.popupId['calculator'], text = _("Field calculator"))
|
|
popupMenu.AppendSeparator()
|
|
popupMenu.AppendSeparator()
|
|
- popupMenu.Append(self.popupID14, text = _("Statistics"))
|
|
|
|
|
|
+ popupMenu.Append(self.popupId['stats'], text = _("Statistics"))
|
|
|
|
|
|
if not self.pages['manageTable']:
|
|
if not self.pages['manageTable']:
|
|
popupMenu.AppendSeparator()
|
|
popupMenu.AppendSeparator()
|
|
- self.popupID14 = wx.NewId()
|
|
|
|
- popupMenu.Append(self.popupID14, text = _("Add column"))
|
|
|
|
|
|
+ self.popupId['addCol'] = wx.NewId()
|
|
|
|
+ popupMenu.Append(self.popupId['addCol'], text = _("Add column"))
|
|
if not self.dbMgrData['editable']:
|
|
if not self.dbMgrData['editable']:
|
|
- popupMenu.Enable(self.popupID14, False)
|
|
|
|
|
|
+ popupMenu.Enable(self.popupId['addCol'], False)
|
|
|
|
|
|
if not self.dbMgrData['editable']:
|
|
if not self.dbMgrData['editable']:
|
|
- popupMenu.Enable(self.popupID13, False)
|
|
|
|
|
|
+ popupMenu.Enable(self.popupId['calculator'], False)
|
|
|
|
|
|
if not self.dbMgrData['editable'] or \
|
|
if not self.dbMgrData['editable'] or \
|
|
self.columns[self.GetColumn(self._col).GetText()]['ctype'] not in (types.IntType, types.FloatType):
|
|
self.columns[self.GetColumn(self._col).GetText()]['ctype'] not in (types.IntType, types.FloatType):
|
|
- popupMenu.Enable(self.popupID3, False)
|
|
|
|
- popupMenu.Enable(self.popupID14, False)
|
|
|
|
-
|
|
|
|
- subMenu.Append(self.popupID4, text = _("Area size"))
|
|
|
|
- subMenu.Append(self.popupID5, text = _("Line length"))
|
|
|
|
- subMenu.Append(self.popupID6, text = _("Compactness of an area"))
|
|
|
|
- subMenu.Append(self.popupID7, text = _("Fractal dimension of boundary defining a polygon"))
|
|
|
|
- subMenu.Append(self.popupID8, text = _("Perimeter length of an area"))
|
|
|
|
- subMenu.Append(self.popupID9, text = _("Number of features for each category"))
|
|
|
|
- subMenu.Append(self.popupID10, text = _("Slope steepness of 3D line"))
|
|
|
|
- subMenu.Append(self.popupID11, text = _("Line sinuousity"))
|
|
|
|
- subMenu.Append(self.popupID12, text = _("Line azimuth"))
|
|
|
|
-
|
|
|
|
- self.Bind (wx.EVT_MENU, self.OnColumnSortAsc, id = self.popupID10)
|
|
|
|
- self.Bind (wx.EVT_MENU, self.OnColumnSortDesc, id = self.popupID2)
|
|
|
|
- self.Bind(wx.EVT_MENU, self.OnFieldCalculator, id = self.popupID13)
|
|
|
|
- self.Bind(wx.EVT_MENU, self.OnFieldStatistics, id = self.popupID14)
|
|
|
|
|
|
+ popupMenu.Enable(self.popupId['calculate'], False)
|
|
|
|
+
|
|
|
|
+ subMenu.Append(self.popupId['area'], text = _("Area size"))
|
|
|
|
+ subMenu.Append(self.popupId['length'], text = _("Line length"))
|
|
|
|
+ subMenu.Append(self.popupId['compact'], text = _("Compactness of an area"))
|
|
|
|
+ subMenu.Append(self.popupId['fractal'], text = _("Fractal dimension of boundary defining a polygon"))
|
|
|
|
+ subMenu.Append(self.popupId['perimeter'], text = _("Perimeter length of an area"))
|
|
|
|
+ subMenu.Append(self.popupId['ncats'], text = _("Number of features for each category"))
|
|
|
|
+ subMenu.Append(self.popupId['slope'], text = _("Slope steepness of 3D line"))
|
|
|
|
+ subMenu.Append(self.popupId['lsin'], text = _("Line sinuousity"))
|
|
|
|
+ subMenu.Append(self.popupId['lazimuth'], text = _("Line azimuth"))
|
|
|
|
+
|
|
|
|
+ self.Bind (wx.EVT_MENU, self.OnColumnSortAsc, id = self.popupId['sortAsc'])
|
|
|
|
+ self.Bind (wx.EVT_MENU, self.OnColumnSortDesc, id = self.popupId['sortDesc'])
|
|
|
|
+ self.Bind(wx.EVT_MENU, self.OnFieldCalculator, id = self.popupId['calculator'])
|
|
|
|
+ self.Bind(wx.EVT_MENU, self.OnFieldStatistics, id = self.popupId['stats'])
|
|
if not self.pages['manageTable']:
|
|
if not self.pages['manageTable']:
|
|
- self.Bind(wx.EVT_MENU, self.OnAddColumn, id = self.popupID14)
|
|
|
|
|
|
+ self.Bind(wx.EVT_MENU, self.OnAddColumn, id = self.popupId['addCol'])
|
|
|
|
|
|
- for id in (self.popupID4, self.popupID5, self.popupID6,
|
|
|
|
- self.popupID7, self.popupID8, self.popupID9,
|
|
|
|
- self.popupID10, self.popupID11, self.popupID12):
|
|
|
|
|
|
+ for id in (self.popupId['area'], self.popupId['length'], self.popupId['compact'],
|
|
|
|
+ self.popupId['fractal'], self.popupId['perimeter'], self.popupId['ncats'],
|
|
|
|
+ self.popupId['slope'], self.popupId['lsin'], self.popupId['lazimuth']):
|
|
self.Bind(wx.EVT_MENU, self.OnColumnCompute, id = id)
|
|
self.Bind(wx.EVT_MENU, self.OnColumnCompute, id = id)
|
|
|
|
|
|
self.PopupMenu(popupMenu)
|
|
self.PopupMenu(popupMenu)
|
|
@@ -489,23 +488,23 @@ class VirtualAttributeList(wx.ListCtrl,
|
|
id = event.GetId()
|
|
id = event.GetId()
|
|
|
|
|
|
option = None
|
|
option = None
|
|
- if id == self.popupID4:
|
|
|
|
|
|
+ if id == self.popupId['area']:
|
|
option = 'area'
|
|
option = 'area'
|
|
- elif id == self.popupID5:
|
|
|
|
|
|
+ elif id == self.popupId['length']:
|
|
option = 'length'
|
|
option = 'length'
|
|
- elif id == self.popupID6:
|
|
|
|
|
|
+ elif id == self.popupId['compact']:
|
|
option = 'compact'
|
|
option = 'compact'
|
|
- elif id == self.popupID7:
|
|
|
|
|
|
+ elif id == self.popupId['fractal']:
|
|
option = 'fd'
|
|
option = 'fd'
|
|
- elif id == self.popupID8:
|
|
|
|
|
|
+ elif id == self.popupId['perimeter']:
|
|
option = 'perimeter'
|
|
option = 'perimeter'
|
|
- elif id == self.popupID9:
|
|
|
|
|
|
+ elif id == self.popupId['ncats']:
|
|
option = 'count'
|
|
option = 'count'
|
|
- elif id == self.popupID10:
|
|
|
|
|
|
+ elif id == self.popupId['slope']:
|
|
option = 'slope'
|
|
option = 'slope'
|
|
- elif id == self.popupID11:
|
|
|
|
|
|
+ elif id == self.popupId['lsin']:
|
|
option = 'sinuous'
|
|
option = 'sinuous'
|
|
- elif id == self.popupID12:
|
|
|
|
|
|
+ elif id == self.popupId['lazimuth']:
|
|
option = 'azimuth'
|
|
option = 'azimuth'
|
|
|
|
|
|
if not option:
|
|
if not option:
|
|
@@ -3389,17 +3388,21 @@ class FieldStatistics(wx.Frame):
|
|
"""
|
|
"""
|
|
self.parent = parent
|
|
self.parent = parent
|
|
wx.Frame.__init__(self, parent, id, style = style, **kwargs)
|
|
wx.Frame.__init__(self, parent, id, style = style, **kwargs)
|
|
|
|
+
|
|
self.SetTitle(_("Field statistics"))
|
|
self.SetTitle(_("Field statistics"))
|
|
|
|
+ self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
|
|
|
|
+
|
|
|
|
+ self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
|
|
|
|
|
|
- self.sp = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY, size=(300, 200),
|
|
|
|
|
|
+ self.sp = scrolled.ScrolledPanel(parent=self.panel, id=wx.ID_ANY, size=(250, 150),
|
|
style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="Statistics" )
|
|
style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="Statistics" )
|
|
self.text = wx.TextCtrl(parent=self.sp, id=wx.ID_ANY, style=wx.TE_MULTILINE|wx.TE_READONLY)
|
|
self.text = wx.TextCtrl(parent=self.sp, id=wx.ID_ANY, style=wx.TE_MULTILINE|wx.TE_READONLY)
|
|
self.text.SetBackgroundColour("white")
|
|
self.text.SetBackgroundColour("white")
|
|
|
|
|
|
# buttons
|
|
# buttons
|
|
- self.btnClipboard = wx.Button(self, id = wx.ID_COPY)
|
|
|
|
|
|
+ self.btnClipboard = wx.Button(parent=self.panel, id = wx.ID_COPY)
|
|
self.btnClipboard.SetToolTipString(_("Copy statistics the clipboard (Ctrl+C)"))
|
|
self.btnClipboard.SetToolTipString(_("Copy statistics the clipboard (Ctrl+C)"))
|
|
- self.btnCancel = wx.Button(self, wx.ID_CLOSE)
|
|
|
|
|
|
+ self.btnCancel = wx.Button(parent=self.panel, id=wx.ID_CLOSE)
|
|
self.btnCancel.SetDefault()
|
|
self.btnCancel.SetDefault()
|
|
|
|
|
|
# bindings
|
|
# bindings
|
|
@@ -3423,7 +3426,7 @@ class FieldStatistics(wx.Frame):
|
|
sizer.Add(item = self.sp, proportion = 1, flag = wx.GROW |
|
|
sizer.Add(item = self.sp, proportion = 1, flag = wx.GROW |
|
|
wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 3)
|
|
wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 3)
|
|
|
|
|
|
- line = wx.StaticLine(parent = self, id = wx.ID_ANY,
|
|
|
|
|
|
+ line = wx.StaticLine(parent = self.panel, id = wx.ID_ANY,
|
|
size = (20, -1), style = wx.LI_HORIZONTAL)
|
|
size = (20, -1), style = wx.LI_HORIZONTAL)
|
|
sizer.Add(item = line, proportion = 0,
|
|
sizer.Add(item = line, proportion = 0,
|
|
flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
|
|
flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border = 3)
|
|
@@ -3435,8 +3438,8 @@ class FieldStatistics(wx.Frame):
|
|
flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
|
|
flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
|
|
sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
|
|
sizer.Add(item = btnSizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
|
|
|
|
|
|
- self.SetSizer(sizer)
|
|
|
|
- sizer.Fit(self)
|
|
|
|
|
|
+ self.panel.SetSizer(sizer)
|
|
|
|
+ sizer.Fit(self.panel)
|
|
|
|
|
|
def OnCopy(self, event):
|
|
def OnCopy(self, event):
|
|
"""!Copy the statistics to the clipboard
|
|
"""!Copy the statistics to the clipboard
|
|
@@ -3456,14 +3459,23 @@ class FieldStatistics(wx.Frame):
|
|
|
|
|
|
def Update(self, driver, database, table, column):
|
|
def Update(self, driver, database, table, column):
|
|
"""!Update statistics for given column
|
|
"""!Update statistics for given column
|
|
-
|
|
|
|
|
|
+
|
|
:param: column column name
|
|
:param: column column name
|
|
"""
|
|
"""
|
|
|
|
+ if driver == 'dbf':
|
|
|
|
+ GError(parent=self,
|
|
|
|
+ message=_("Statistics is not support for DBF tables."))
|
|
|
|
+ self.Close()
|
|
|
|
+ return
|
|
|
|
+
|
|
fd, sqlFilePath = tempfile.mkstemp(text=True)
|
|
fd, sqlFilePath = tempfile.mkstemp(text=True)
|
|
sqlFile = open(sqlFilePath, 'w')
|
|
sqlFile = open(sqlFilePath, 'w')
|
|
- stats = ['count', 'min', 'max', 'avg', 'sum']
|
|
|
|
|
|
+ stats = ['count', 'min', 'max', 'avg', 'sum', 'null']
|
|
for fn in stats:
|
|
for fn in stats:
|
|
- sqlFile.write('select %s(%s) from %s;%s' % (fn, column, table, os.linesep))
|
|
|
|
|
|
+ if fn == 'null':
|
|
|
|
+ sqlFile.write('select count(*) from %s where %s is null;%s' % (table, column, os.linesep))
|
|
|
|
+ else:
|
|
|
|
+ sqlFile.write('select %s(%s) from %s;%s' % (fn, column, table, os.linesep))
|
|
sqlFile.close()
|
|
sqlFile.close()
|
|
|
|
|
|
dataStr = RunCommand('db.select',
|
|
dataStr = RunCommand('db.select',
|
|
@@ -3474,15 +3486,40 @@ class FieldStatistics(wx.Frame):
|
|
driver = driver,
|
|
driver = driver,
|
|
database = database)
|
|
database = database)
|
|
if not dataStr:
|
|
if not dataStr:
|
|
|
|
+ GError(parent = self.parent,
|
|
|
|
+ message = _("Unable to calculte statistics."))
|
|
|
|
+ self.Close()
|
|
return
|
|
return
|
|
|
|
+
|
|
dataLines = dataStr.splitlines()
|
|
dataLines = dataStr.splitlines()
|
|
if len(dataLines) != len(stats):
|
|
if len(dataLines) != len(stats):
|
|
GError(parent = self.parent,
|
|
GError(parent = self.parent,
|
|
message = _("Unable to calculte statistics. "
|
|
message = _("Unable to calculte statistics. "
|
|
"Invalid number of lines %d (should be %d).") % (len(dataLines), len(stats)))
|
|
"Invalid number of lines %d (should be %d).") % (len(dataLines), len(stats)))
|
|
-
|
|
|
|
|
|
+ self.Close()
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # calculate stddev
|
|
|
|
+ avg = float(dataLines[stats.index('avg')])
|
|
|
|
+ count = float(dataLines[stats.index('count')])
|
|
|
|
+ sql = "select (%(column)s - %(avg)f)*(%(column)s - %(avg)f) from %(table)s" % { 'column' : column, 'avg' : avg, 'table' : table }
|
|
|
|
+ dataVar = RunCommand('db.select',
|
|
|
|
+ parent = self.parent,
|
|
|
|
+ read = True,
|
|
|
|
+ flags='c',
|
|
|
|
+ sql = sql,
|
|
|
|
+ driver = driver,
|
|
|
|
+ database = database)
|
|
|
|
+ if not dataVar:
|
|
|
|
+ GWarning(parent = self.parent,
|
|
|
|
+ message = _("Unable to calculte standard deviation."))
|
|
|
|
+ varSum = 0
|
|
|
|
+ for var in dataVar.splitlines():
|
|
|
|
+ varSum += float(var)
|
|
|
|
+ stddev = math.sqrt(varSum/count)
|
|
|
|
+
|
|
self.SetTitle(_("Field statistics <%s>") % column)
|
|
self.SetTitle(_("Field statistics <%s>") % column)
|
|
self.text.Clear()
|
|
self.text.Clear()
|
|
for idx in range(len(stats)):
|
|
for idx in range(len(stats)):
|
|
self.text.AppendText('%s: %s\n' % (stats[idx], dataLines[idx]))
|
|
self.text.AppendText('%s: %s\n' % (stats[idx], dataLines[idx]))
|
|
-
|
|
|
|
|
|
+ self.text.AppendText('stddev: %f\n' % stddev)
|