Skip to content

Commit 713c105

Browse files
committed
Merge pull request #37 from clusterpy/null_values
Null values
2 parents 0c7baa3 + 75de681 commit 713c105

5 files changed

Lines changed: 83 additions & 40 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ a free and Open Source Geographic Information System.
2020
##Cite the plugin
2121
If you are interested in citing this plugin, you can use:
2222

23-
Duque, J.C.; Botero, Sergio (2014). Clusterpy QGIS plugin, Version 0.12-preview RiSE-group (Research in Spatial Economics). EAFIT University. http://www.rise-group.org.
23+
Duque, J.C.; Botero, Sergio (2014). Clusterpy QGIS plugin, Version 0.13-preview RiSE-group (Research in Spatial Economics). EAFIT University. http://www.rise-group.org.
2424

2525
Or this BibTeX entry:
2626
```
2727
@Manual{clusterpy-qgis-plugin,
2828
title = {Clusterpy QGIS plugin,
29-
{Version} 0.12-preview},
29+
{Version} 0.13-preview},
3030
author = {Duque, Juan C. and Botero, Sergio},
3131
organization = {RiSE-group (Research in Spatial Economics). EAFIT University.},
3232
address = {Colombia},

clusterpy_lightdialog.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ def __init__(self):
3939
self.help_browser.setHtml(abouthtml)
4040

4141
class maxpDialog(QtGui.QDialog, Ui_maxp_ui):
42-
DONE_MSG = "Finish"
4342

4443
def __init__(self):
4544
QtGui.QDialog.__init__(self)
@@ -48,6 +47,10 @@ def __init__(self):
4847
QtCore.SIGNAL("currentIndexChanged(int)"),
4948
self.updateThresholdLimits)
5049

50+
self.connect(self.attribute_combo,
51+
QtCore.SIGNAL("currentIndexChanged(int)"),
52+
self.checkAttrValues)
53+
5154
self.connect(self.layer_combo,
5255
QtCore.SIGNAL("currentIndexChanged(int)"),
5356
self.updateAttrCombo)
@@ -77,18 +80,46 @@ def updateAttrCombo(self, newindex):
7780
self.attribute_combo.addItems(fieldNames)
7881
self.threshold_attr_combo.addItems(fieldNames2)
7982

83+
def checkAttrValues(self, newindex):
84+
if newindex > -1:
85+
attributeName = self.attribute_combo.currentText()
86+
self.checkAllValues(attributeName)
87+
88+
def checkAllValues(self, attributeName):
89+
layerIndex = self.layer_combo.currentIndex()
90+
fiterator = self.mc.layer(layerIndex).dataProvider().getFeatures()
91+
92+
valid = True
93+
maximum = 0
94+
minimum = 99999
95+
for feature in fiterator:
96+
val = feature.attribute(attributeName)
97+
try:
98+
minimum = val if val < minimum else minimum
99+
maximum += val
100+
except TypeError:
101+
valid = False
102+
103+
if not valid:
104+
null_message = "Some values are missing.\n" +\
105+
"Check the Attribute Table for NULL or empty values.\n" +\
106+
"Column: " + str(attributeName) + "\n" +\
107+
"Please update the Attribute Table in order to run Max-p."
108+
109+
# Showing a message box might be better to get the user's attention
110+
QtGui.QMessageBox.warning(self, "Clusterpy", null_message)
111+
#self.showMessage("Clusterpy Error", "NULL or Empty Attrs",
112+
# level=QgsMessageBar.CRITICAL)
113+
114+
return minimum, maximum
115+
80116
def updateThresholdLimits(self, newindex):
81117
if newindex > -1:
82118
layerIndex = self.layer_combo.currentIndex()
83119
fiterator = self.mc.layer(layerIndex).dataProvider().getFeatures()
84120
attributeName = self.threshold_attr_combo.currentText()
85121

86-
maximum = 0
87-
minimum = 99999
88-
for feature in fiterator:
89-
val = feature.attribute(attributeName)
90-
minimum = val if val < minimum else minimum
91-
maximum += val
122+
minimum, maximum = self.checkAllValues(attributeName)
92123

93124
self.threshold_spin.setMinimum(minimum)
94125
self.threshold_spin.setMaximum(maximum)
@@ -145,8 +176,8 @@ def finishRun(self, success, outputmsg):
145176
self.okbutton.setEnabled(True)
146177
if success:
147178
self.addToCanvas()
148-
output_msg = "Success. New column added to attribute table. " + outputmsg
149-
self.showMessage("Clusterpy", output_msg, duration=0 )
179+
msg = "Success. New column added to attribute table. " + outputmsg
180+
self.showMessage("Clusterpy", msg, duration=0 )
150181
else:
151182
self.showMessage("Clusterpy Error",
152183
outputmsg,

metadata.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
name=Clusterpy - Spatially constrained clustering
55
qgisMinimumVersion=2.0
66
description=Clusterpy plugin version for QGIS
7-
version=0.12-preview
7+
version=0.13-preview
88
author=RISE Group Universidad EAFIT
99
email=software@rise-group.org
1010

uifiles/about.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ <h2>Research in Spatial Economics</h2>
99
<h3>Cite the Plugin</h3>
1010
If you are interested in citing this plugin, you can use:
1111
<p>
12-
Duque, J.C.; Botero, Sergio (2014). Clusterpy QGIS plugin, Version 0.12-preview RiSE-group (Research in Spatial Economics). EAFIT University. http://www.rise-group.org.
12+
Duque, J.C.; Botero, Sergio (2014). Clusterpy QGIS plugin, Version 0.13-preview RiSE-group (Research in Spatial Economics). EAFIT University. http://www.rise-group.org.
1313
</p>
1414
Or this BibTeX entry:
1515
<pre><code>
1616
@Manual{clusterpy-qgis-plugin,
1717
title = {Clusterpy QGIS plugin,
18-
{Version} 0.12-preview},
18+
{Version} 0.13-preview},
1919
author = {Duque, Juan C. and Botero, Sergio},
2020
organization = {RiSE-group (Research in Spatial Economics). EAFIT University.},
2121
address = {Colombia},

workers.py

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def run(self):
3131
newfields.extend(provider.fields())
3232
newfields.append(maxpfield)
3333

34+
bad_value = -1
3435
clspyfeatures = {}
3536
for feat in provider.getFeatures():
3637
uid = feat.id()
@@ -42,37 +43,48 @@ def run(self):
4243
neighbors.discard(uid)
4344
thresholdval = feat.attribute(self.thresholdattr)
4445
attributeval = feat.attribute(self.attrname)
46+
47+
if thresholdval == None or attributeval == None:
48+
bad_value = uid
49+
break
50+
4551
clspyfeatures[uid] = ClusterpyFeature(uid, thresholdval,
4652
neighbors, attributeval)
4753

4854
outputmsg = None
49-
valid, islands = validtopology(clspyfeatures)
50-
if valid:
51-
self.progress.emit(1.0)
52-
regions = execmaxp(clspyfeatures,
53-
self.threshold,
54-
self.maxit,
55-
self.tabusize,
56-
self.tabumax,
57-
self.progress.emit)
58-
self.progress.emit(95.0)
59-
newlayer = QgsVectorFileWriter( self.output_path,
60-
None,
61-
newfields,
62-
provider.geometryType(),
63-
provider.crs())
55+
valid = True
56+
if bad_value != -1:
57+
valid = False
58+
outputmsg = "Please review feature with ID: " + str(bad_value) +\
59+
" and assign a numeric value to the NULL or empty attributes."
60+
else:
61+
valid, islands = validtopology(clspyfeatures)
62+
if valid:
63+
self.progress.emit(1.0)
64+
regions = execmaxp(clspyfeatures,
65+
self.threshold,
66+
self.maxit,
67+
self.tabusize,
68+
self.tabumax,
69+
self.progress.emit)
70+
self.progress.emit(95.0)
71+
newlayer = QgsVectorFileWriter( self.output_path,
72+
None,
73+
newfields,
74+
provider.geometryType(),
75+
provider.crs())
6476

65-
for area in self.layer.getFeatures():
66-
newarea = QgsFeature()
67-
newarea.setGeometry(area.geometry())
68-
attrs = area.attributes()
69-
attrs.append(regions[area.id()])
70-
newarea.setAttributes(attrs)
71-
newlayer.addFeature(newarea)
77+
for area in self.layer.getFeatures():
78+
newarea = QgsFeature()
79+
newarea.setGeometry(area.geometry())
80+
attrs = area.attributes()
81+
attrs.append(regions[area.id()])
82+
newarea.setAttributes(attrs)
83+
newlayer.addFeature(newarea)
7284

73-
del newlayer
74-
outputmsg = self.output_path
75-
else:
76-
outputmsg = self.ERROR_MSG + str(map(str, islands))
85+
del newlayer
86+
outputmsg = self.output_path
87+
else:
88+
outputmsg = self.ERROR_MSG + str(map(str, islands))
7789
self.progress.emit(100.0)
7890
self.finished.emit(valid, outputmsg)

0 commit comments

Comments
 (0)