|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +"""QGIS Unit tests for QgsGraduatedSymbolRendererV2 |
| 3 | +
|
| 4 | +.. note:: This program is free software; you can redistribute it and/or modify |
| 5 | +it under the terms of the GNU General Public License as published by |
| 6 | +the Free Software Foundation; either version 2 of the License, or |
| 7 | +(at your option) any later version. |
| 8 | +""" |
| 9 | +__author__ = 'Chris Crook' |
| 10 | +__date__ = '3/10/2014' |
| 11 | +__copyright__ = 'Copyright 2014, The QGIS Project' |
| 12 | +# This will get replaced with a git SHA1 when you do a git archive |
| 13 | +__revision__ = '$Format:%H$' |
| 14 | + |
| 15 | +import qgis |
| 16 | +from utilities import ( |
| 17 | + unittest, |
| 18 | + TestCase, |
| 19 | + getQgisTestApp, |
| 20 | + ) |
| 21 | +from qgis.core import ( |
| 22 | + QgsGraduatedSymbolRendererV2, |
| 23 | + QgsRendererRangeV2, |
| 24 | + QgsRendererRangeV2LabelFormat, |
| 25 | + QgsMarkerSymbolV2, |
| 26 | + QgsVectorGradientColorRampV2, |
| 27 | + QgsVectorLayer, |
| 28 | + QgsFeature, |
| 29 | + QgsGeometry, |
| 30 | + QgsPoint, |
| 31 | + QgsSymbolV2, |
| 32 | + QgsSymbolLayerV2Utils, |
| 33 | + ) |
| 34 | +from PyQt4.QtCore import ( |
| 35 | + Qt, |
| 36 | + ) |
| 37 | +from PyQt4.QtXml import ( |
| 38 | + QDomDocument, |
| 39 | + ) |
| 40 | +from PyQt4.QtGui import ( |
| 41 | + QColor, |
| 42 | + ) |
| 43 | + |
| 44 | +QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp() |
| 45 | + |
| 46 | +#=========================================================== |
| 47 | +# Utility functions |
| 48 | + |
| 49 | +def createMarkerSymbol(): |
| 50 | + symbol=QgsMarkerSymbolV2.createSimple({ |
| 51 | + "color":"100,150,50", |
| 52 | + "name":"square", |
| 53 | + "size":"3.0" |
| 54 | + }) |
| 55 | + return symbol |
| 56 | + |
| 57 | +def createMemoryLayer(values): |
| 58 | + ml=QgsVectorLayer("Point?crs=epsg:4236&field=id:integer&field=value:double", |
| 59 | + "test_data", "memory") |
| 60 | + # Data as list of x, y, id, value |
| 61 | + assert ml.isValid() |
| 62 | + pr=ml.dataProvider() |
| 63 | + fields=pr.fields() |
| 64 | + for id, value in enumerate(values): |
| 65 | + x=id*10.0 |
| 66 | + feat=QgsFeature(fields) |
| 67 | + feat['id']=id |
| 68 | + feat['value']=value |
| 69 | + g=QgsGeometry.fromPoint(QgsPoint(x,x)) |
| 70 | + feat.setGeometry(g) |
| 71 | + pr.addFeatures( [feat] ) |
| 72 | + ml.updateExtents() |
| 73 | + return ml |
| 74 | + |
| 75 | +def createColorRamp(): |
| 76 | + return QgsVectorGradientColorRampV2( |
| 77 | + QColor(255,0,0), |
| 78 | + QColor(0,0,255) |
| 79 | + ) |
| 80 | + |
| 81 | +def createLabelFormat(): |
| 82 | + format=QgsRendererRangeV2LabelFormat() |
| 83 | + template="%1 - %2 metres" |
| 84 | + precision=5 |
| 85 | + format.setFormat(template) |
| 86 | + format.setPrecision(precision) |
| 87 | + format.setTrimTrailingZeroes(True) |
| 88 | + return format |
| 89 | + |
| 90 | +# Note: Dump functions are not designed for a user friendly dump, just |
| 91 | +# for a moderately compact representation of a rendererer that is independent |
| 92 | +# of the renderer source code and so appropriate for use in unit tests. |
| 93 | + |
| 94 | +def dumpRangeBreaks( ranges ): |
| 95 | + return dumpRangeList(ranges,breaksOnly=True) |
| 96 | + |
| 97 | +def dumpRangeLabels( ranges ): |
| 98 | + return dumpRangeList(ranges,labelsOnly=True) |
| 99 | + |
| 100 | +def dumpLabelFormat( format ): |
| 101 | + return ( |
| 102 | + ':'+format.format()+ |
| 103 | + ':'+str(format.precision())+ |
| 104 | + ':'+str(format.trimTrailingZeroes())+ |
| 105 | + ':') |
| 106 | + |
| 107 | +def dumpRangeList( rlist, breaksOnly=False,labelsOnly=False ): |
| 108 | + rstr='(' |
| 109 | + format="{0:.4f}-{1:.4f}" |
| 110 | + if not breaksOnly: |
| 111 | + format=format+":{2}:{3}:{4}:" |
| 112 | + if labelsOnly: |
| 113 | + format='{2}' |
| 114 | + for r in rlist: |
| 115 | + rstr = rstr + format.format( |
| 116 | + r.lowerValue(), |
| 117 | + r.upperValue(), |
| 118 | + r.label(), |
| 119 | + r.symbol().dump(), |
| 120 | + r.renderState(), |
| 121 | + ) + "," |
| 122 | + return rstr+')' |
| 123 | + |
| 124 | +# Crude dump for deterministic ramp - just dumps colors at a range of values |
| 125 | + |
| 126 | +def dumpColorRamp( ramp ): |
| 127 | + if ramp is None: |
| 128 | + return ':None:' |
| 129 | + rampstr=':' |
| 130 | + for x in (0.0,0.33,0.66,1.0): |
| 131 | + rampstr = rampstr+ramp.color(x).name()+':' |
| 132 | + return rampstr |
| 133 | + |
| 134 | +def dumpGraduatedRenderer( r ): |
| 135 | + rstr=':' |
| 136 | + rstr=rstr+r.classAttribute()+':' |
| 137 | + rstr=rstr+str(r.mode())+':' |
| 138 | + symbol=r.sourceSymbol() |
| 139 | + if symbol is None: |
| 140 | + rstr=rstr+'None'+':' |
| 141 | + else: |
| 142 | + rstr=rstr+symbol.dump()+':' |
| 143 | + rstr=rstr+dumpColorRamp(r.sourceColorRamp()) |
| 144 | + rstr=rstr+str(r.invertedColorRamp())+':' |
| 145 | + rstr=rstr+dumpRangeList(r.ranges()) |
| 146 | + rstr=rstr+r.rotationField()+':' |
| 147 | + rstr=rstr+r.sizeScaleField()+':' |
| 148 | + rstr=rstr+str(r.scaleMethod())+':' |
| 149 | + return rstr |
| 150 | + |
| 151 | +#================================================================= |
| 152 | +# Tests |
| 153 | + |
| 154 | +class TestQgsGraduatedSymbolRendererV2(TestCase): |
| 155 | + |
| 156 | + def testQgsRendererRangeV2_1(self): |
| 157 | + """Test QgsRendererRangeV2 getter/setter functions""" |
| 158 | + range=QgsRendererRangeV2() |
| 159 | + self.assertTrue(range) |
| 160 | + lower=123.45 |
| 161 | + upper=234.56 |
| 162 | + label="Test label" |
| 163 | + symbol=createMarkerSymbol() |
| 164 | + range.setLowerValue(lower) |
| 165 | + self.assertEqual(range.lowerValue(),lower,"Lower value getter/setter failed") |
| 166 | + range.setUpperValue(upper) |
| 167 | + self.assertEqual(range.upperValue(),upper,"Upper value getter/setter failed") |
| 168 | + range.setLabel(label) |
| 169 | + self.assertEqual(range.label(),label,"Label getter/setter failed") |
| 170 | + range.setRenderState(True) |
| 171 | + self.assertTrue(range.renderState(),"Render state getter/setter failed") |
| 172 | + range.setRenderState(False) |
| 173 | + self.assertFalse(range.renderState(),"Render state getter/setter failed") |
| 174 | + range.setSymbol(symbol.clone()) |
| 175 | + self.assertEqual(symbol.dump(),range.symbol().dump(),"Symbol getter/setter failed") |
| 176 | + range2=QgsRendererRangeV2(lower,upper,symbol.clone(),label,False) |
| 177 | + self.assertEqual(range2.lowerValue(),lower,"Lower value from constructor failed") |
| 178 | + self.assertEqual(range2.upperValue(),upper,"Upper value from constructor failed") |
| 179 | + self.assertEqual(range2.label(),label,"Label from constructor failed") |
| 180 | + self.assertEqual(range2.symbol().dump(),symbol.dump(),"Symbol from constructor failed") |
| 181 | + self.assertFalse(range2.renderState(),"Render state getter/setter failed") |
| 182 | + |
| 183 | + def testQgsRendererRangeV2LabelFormat_1(self): |
| 184 | + """Test QgsRendererRangeV2LabelFormat getter/setter functions""" |
| 185 | + format=QgsRendererRangeV2LabelFormat() |
| 186 | + self.assertTrue(format,"QgsRendererRangeV2LabelFomat construction failed") |
| 187 | + template="%1 - %2 metres" |
| 188 | + precision=5 |
| 189 | + format.setFormat(template) |
| 190 | + self.assertEqual(format.format(),template,"Format getter/setter failed") |
| 191 | + format.setPrecision(precision) |
| 192 | + self.assertEqual(format.precision(),precision,"Precision getter/setter failed") |
| 193 | + format.setTrimTrailingZeroes(True) |
| 194 | + self.assertTrue(format.trimTrailingZeroes(),"TrimTrailingZeroes getter/setter failed") |
| 195 | + format.setTrimTrailingZeroes(False) |
| 196 | + self.assertFalse(format.trimTrailingZeroes(),"TrimTrailingZeroes getter/setter failed") |
| 197 | + minprecision=-6; |
| 198 | + maxprecision=15; |
| 199 | + self.assertEqual(QgsRendererRangeV2LabelFormat.MinPrecision,minprecision,"Minimum precision != -6") |
| 200 | + self.assertEqual(QgsRendererRangeV2LabelFormat.MaxPrecision,maxprecision,"Maximum precision != 15") |
| 201 | + format.setPrecision(-10) |
| 202 | + self.assertEqual(format.precision(),minprecision,"Minimum precision not enforced") |
| 203 | + format.setPrecision(20) |
| 204 | + self.assertEqual(format.precision(),maxprecision,"Maximum precision not enforced") |
| 205 | + |
| 206 | + def testQgsRendererRangeV2LabelFormat_2(self): |
| 207 | + """Test QgsRendererRangeV2LabelFormat number format""" |
| 208 | + format=QgsRendererRangeV2LabelFormat() |
| 209 | + # Tests have precision, trim, value, expected |
| 210 | + # (Note: Not sure what impact of locale is on these tests) |
| 211 | + tests=( |
| 212 | + (2,False,1.0,'1.00'), |
| 213 | + (2,True,1.0,'1'), |
| 214 | + (2,False,1.234,'1.23'), |
| 215 | + (2,True,1.234,'1.23'), |
| 216 | + (2,False,1.236,'1.24'), |
| 217 | + (2,False,-1.236,'-1.24'), |
| 218 | + (2,False,-0.004,'0.00'), |
| 219 | + (2,True,1.002,'1'), |
| 220 | + (2,True,1.006,'1.01'), |
| 221 | + (2,True,1.096,'1.1'), |
| 222 | + (3,True,1.096,'1.096'), |
| 223 | + (-2,True,1496.45,'1500'), |
| 224 | + (-2,True,149.45,'100'), |
| 225 | + (-2,True,79.45,'100'), |
| 226 | + (-2,True,49.45,'0'), |
| 227 | + (-2,True,-49.45,'0'), |
| 228 | + (-2,True,-149.45,'-100'), |
| 229 | + ) |
| 230 | + for f in tests: |
| 231 | + precision,trim,value,expected=f |
| 232 | + format.setPrecision(precision) |
| 233 | + format.setTrimTrailingZeroes(trim) |
| 234 | + result=format.formatNumber(value) |
| 235 | + testname="{0}:{1}:{2}".format(precision,trim,value) |
| 236 | + self.assertEqual(result,expected, |
| 237 | + "Number format error {0}:{1}:{2} => {3}".format( |
| 238 | + precision,trim,value,result)) |
| 239 | + |
| 240 | + # Label tests - label format, expected result. |
| 241 | + # Labels will be evaluated with lower=1.23 upper=2.34, precision=2 |
| 242 | + ltests=( |
| 243 | + ("%1 - %2","1.23 - 2.34"), |
| 244 | + ("%1","1.23"), |
| 245 | + ("%2","2.34"), |
| 246 | + ("%2%","2.34%"), |
| 247 | + ("%1%1","1.231.23"), |
| 248 | + ("from %1 to %2 metres","from 1.23 to 2.34 metres"), |
| 249 | + ("from %2 to %1 metres","from 2.34 to 1.23 metres"), |
| 250 | + ) |
| 251 | + format.setPrecision(2) |
| 252 | + format.setTrimTrailingZeroes(False) |
| 253 | + lower=1.232 |
| 254 | + upper=2.339 |
| 255 | + for t in ltests: |
| 256 | + label,expected=t |
| 257 | + format.setFormat(label) |
| 258 | + result=format.labelForLowerUpper(lower,upper) |
| 259 | + self.assertEqual(result,expected,"Label format error {0} => {1}".format( |
| 260 | + label,result)) |
| 261 | + |
| 262 | + range=QgsRendererRangeV2() |
| 263 | + range.setLowerValue(lower) |
| 264 | + range.setUpperValue(upper) |
| 265 | + label=ltests[0][0] |
| 266 | + format.setFormat(label) |
| 267 | + result=format.labelForRange(range) |
| 268 | + self.assertEqual(result,ltests[0][1],"Label for range error {0} => {1}".format( |
| 269 | + label,result)) |
| 270 | + |
| 271 | + def testQgsGraduatedSymbolRendererV2_1(self): |
| 272 | + """Test QgsGraduatedSymbolRendererV2: Basic get/set functions """ |
| 273 | + |
| 274 | + # Create a renderer |
| 275 | + renderer=QgsGraduatedSymbolRendererV2() |
| 276 | + |
| 277 | + symbol=createMarkerSymbol() |
| 278 | + renderer.setSourceSymbol(symbol.clone()) |
| 279 | + self.assertEqual(symbol.dump(),renderer.sourceSymbol().dump(),"Get/set renderer source symbol") |
| 280 | + |
| 281 | + attr='"value"*"value"' |
| 282 | + renderer.setClassAttribute(attr) |
| 283 | + self.assertEqual(attr,renderer.classAttribute(),"Get/set renderer class attribute") |
| 284 | + |
| 285 | + for m in ( |
| 286 | + QgsGraduatedSymbolRendererV2.Custom, |
| 287 | + QgsGraduatedSymbolRendererV2.EqualInterval, |
| 288 | + QgsGraduatedSymbolRendererV2.Quantile, |
| 289 | + QgsGraduatedSymbolRendererV2.Jenks, |
| 290 | + QgsGraduatedSymbolRendererV2.Pretty, |
| 291 | + QgsGraduatedSymbolRendererV2.StdDev, |
| 292 | + ): |
| 293 | + renderer.setMode(m) |
| 294 | + self.assertEqual(m,renderer.mode(),"Get/set renderer mode") |
| 295 | + |
| 296 | + format=createLabelFormat() |
| 297 | + renderer.setLabelFormat(format) |
| 298 | + self.assertEqual( |
| 299 | + dumpLabelFormat(format), |
| 300 | + dumpLabelFormat(renderer.labelFormat()), |
| 301 | + "Get/set renderer label format") |
| 302 | + |
| 303 | + ramp=createColorRamp() |
| 304 | + renderer.setSourceColorRamp(ramp) |
| 305 | + self.assertEqual( |
| 306 | + dumpColorRamp(ramp), |
| 307 | + dumpColorRamp(renderer.sourceColorRamp()), |
| 308 | + "Get/set renderer color ramp") |
| 309 | + |
| 310 | + renderer.setInvertedColorRamp(True) |
| 311 | + self.assertTrue(renderer.invertedColorRamp(), |
| 312 | + "Get/set renderer inverted color ramp") |
| 313 | + renderer.setInvertedColorRamp(False) |
| 314 | + self.assertFalse(renderer.invertedColorRamp(), |
| 315 | + "Get/set renderer inverted color ramp") |
| 316 | + |
| 317 | + value='"value"*2' |
| 318 | + exp=QgsSymbolLayerV2Utils.fieldOrExpressionToExpression(value) |
| 319 | + valuestr=QgsSymbolLayerV2Utils.fieldOrExpressionFromExpression(exp) |
| 320 | + renderer.setRotationField(value) |
| 321 | + self.assertEqual(valuestr,renderer.rotationField(), |
| 322 | + "Get/set renderer rotation field") |
| 323 | + |
| 324 | + value='"value"*3' |
| 325 | + exp=QgsSymbolLayerV2Utils.fieldOrExpressionToExpression(value) |
| 326 | + valuestr=QgsSymbolLayerV2Utils.fieldOrExpressionFromExpression(exp) |
| 327 | + renderer.setSizeScaleField(value) |
| 328 | + self.assertEqual(valuestr,renderer.sizeScaleField(), |
| 329 | + "Get/set renderer size scale field") |
| 330 | + |
| 331 | + |
| 332 | + renderer.setSourceColorRamp(ramp) |
| 333 | + self.assertEqual( |
| 334 | + dumpColorRamp(ramp), |
| 335 | + dumpColorRamp(renderer.sourceColorRamp()), |
| 336 | + "Get/set renderer color ramp") |
| 337 | + |
| 338 | + for sm in ( |
| 339 | + QgsSymbolV2.ScaleArea, |
| 340 | + QgsSymbolV2.ScaleDiameter, |
| 341 | + ): |
| 342 | + renderer.setScaleMethod(sm) |
| 343 | + self.assertEqual(str(sm),str(renderer.scaleMethod()), |
| 344 | + "Get/set renderer scale method") |
| 345 | + |
| 346 | + |
| 347 | + |
| 348 | + def testQgsGraduatedSymbolRendererV2_2(self): |
| 349 | + """Test QgsGraduatedSymbolRendererV2: Adding /removing/editing classes """ |
| 350 | + # Create a renderer |
| 351 | + renderer=QgsGraduatedSymbolRendererV2() |
| 352 | + symbol=createMarkerSymbol() |
| 353 | + renderer.setSourceSymbol(symbol.clone()) |
| 354 | + symbol.setColor(QColor(255,0,0)) |
| 355 | + |
| 356 | + # Add class without start and end ranges |
| 357 | + |
| 358 | + renderer.addClass(symbol.clone()) |
| 359 | + renderer.addClass(symbol.clone()) |
| 360 | + renderer.updateRangeLabel(1,'Second range') |
| 361 | + renderer.updateRangeLowerValue(1,10.0) |
| 362 | + renderer.updateRangeUpperValue(1,25.0) |
| 363 | + renderer.updateRangeRenderState(1,False) |
| 364 | + symbol.setColor(QColor(0,0,255)) |
| 365 | + renderer.updateRangeSymbol(1,symbol.clone()) |
| 366 | + |
| 367 | + # Add as a rangeobject |
| 368 | + symbol.setColor(QColor(0,255,0)) |
| 369 | + range=QgsRendererRangeV2(20.0,25.5,symbol.clone(),'Third range',False) |
| 370 | + renderer.addClassRange(range) |
| 371 | + |
| 372 | + # Add class by lower and upper |
| 373 | + renderer.addClassLowerUpper(25.5,30.5) |
| 374 | + # (Update label for sorting tests) |
| 375 | + renderer.updateRangeLabel(3,'Another range') |
| 376 | + |
| 377 | + rangeListStr=dumpRangeList(renderer.ranges()) |
| 378 | + self.assertEqual( |
| 379 | + dumpRangeLabels(renderer.ranges()), |
| 380 | + '(0.0 - 0.0,Second range,Third range,Another range,)', |
| 381 | + 'Added ranges labels not correct') |
| 382 | + self.assertEqual( |
| 383 | + dumpRangeBreaks(renderer.ranges()), |
| 384 | + '(0.0000-0.0000,10.0000-25.0000,20.0000-25.5000,25.5000-30.5000,)', |
| 385 | + 'Added ranges lower/upper values not correct') |
| 386 | + |
| 387 | + # Check that clone function works |
| 388 | + |
| 389 | + renderer2=renderer.clone() |
| 390 | + self.assertEqual( |
| 391 | + dumpGraduatedRenderer(renderer), |
| 392 | + dumpGraduatedRenderer(renderer2), |
| 393 | + "clone function doesn't replicate renderer properly" |
| 394 | + ) |
| 395 | + |
| 396 | + # Check save and reload from Dom works |
| 397 | + |
| 398 | + doc=QDomDocument() |
| 399 | + element=renderer.save(doc) |
| 400 | + renderer2=QgsGraduatedSymbolRendererV2.create(element) |
| 401 | + self.assertEqual( |
| 402 | + dumpGraduatedRenderer(renderer), |
| 403 | + dumpGraduatedRenderer(renderer2), |
| 404 | + "Save/create from DOM doesn't replicate renderer properly" |
| 405 | + ) |
| 406 | + |
| 407 | + # Check sorting |
| 408 | + |
| 409 | + renderer.sortByLabel() |
| 410 | + self.assertEqual( |
| 411 | + dumpRangeList(renderer.ranges(),labelsOnly=True), |
| 412 | + '(0.0 - 0.0,Another range,Second range,Third range,)', |
| 413 | + 'sortByLabel not correct') |
| 414 | + renderer.sortByValue() |
| 415 | + self.assertEqual( |
| 416 | + dumpRangeBreaks(renderer.ranges()), |
| 417 | + '(0.0000-0.0000,10.0000-25.0000,20.0000-25.5000,25.5000-30.5000,)', |
| 418 | + 'sortByValue not correct') |
| 419 | + renderer.sortByValue(Qt.DescendingOrder) |
| 420 | + self.assertEqual( |
| 421 | + dumpRangeBreaks(renderer.ranges()), |
| 422 | + '(25.5000-30.5000,20.0000-25.5000,10.0000-25.0000,0.0000-0.0000,)', |
| 423 | + 'sortByValue descending not correct') |
| 424 | + |
| 425 | + # Check deleting |
| 426 | + |
| 427 | + renderer.deleteClass(2) |
| 428 | + self.assertEqual( |
| 429 | + dumpRangeBreaks(renderer.ranges()), |
| 430 | + '(25.5000-30.5000,20.0000-25.5000,0.0000-0.0000,)', |
| 431 | + 'deleteClass not correct') |
| 432 | + |
| 433 | + renderer.deleteAllClasses() |
| 434 | + self.assertEqual(len(renderer.ranges()),0,"deleteAllClasses didn't delete all") |
| 435 | + |
| 436 | + |
| 437 | +# void addClass( QgsSymbolV2* symbol ); |
| 438 | +# //! @note available in python bindings as addClassRange |
| 439 | +# void addClass( QgsRendererRangeV2 range ) /PyName=addClassRange/; |
| 440 | +# //! @note available in python bindings as addClassLowerUpper |
| 441 | +# void addClass( double lower, double upper ) /PyName=addClassLowerUpper/; |
| 442 | +# void deleteClass( int idx ); |
| 443 | +# void deleteAllClasses(); |
| 444 | + |
| 445 | + def testQgsGraduatedSymbolRendererV2_3(self): |
| 446 | + """Test QgsGraduatedSymbolRendererV2: Reading attribute data, calculating classes """ |
| 447 | + |
| 448 | + # Create a renderer |
| 449 | + renderer=QgsGraduatedSymbolRendererV2() |
| 450 | + symbol=createMarkerSymbol() |
| 451 | + renderer.setSourceSymbol(symbol.clone()) |
| 452 | + |
| 453 | + |
| 454 | + |
| 455 | + # Test retrieving data values from a layer |
| 456 | + ml=createMemoryLayer((1.2,0.5,5.0,1.0,1.0,1.2)) |
| 457 | + # ... by attribute |
| 458 | + renderer.setClassAttribute("value") |
| 459 | + self.assertEqual(renderer.classAttribute(),"value","Error in set/get classAttribute") |
| 460 | + data=renderer.getDataValues(ml) |
| 461 | + datastr=':'.join([str(x) for x in data]) |
| 462 | + self.assertEqual(datastr,'1.2:0.5:5.0:1.0:1.0:1.2',"Error returning field data") |
| 463 | + # ... by expression |
| 464 | + renderer.setClassAttribute('"value"*"value"') |
| 465 | + self.assertEqual(renderer.classAttribute(),'"value"*"value"',"Error in set/get classAttribute") |
| 466 | + data=renderer.getDataValues(ml) |
| 467 | + datastr=':'.join([str(x) for x in data]) |
| 468 | + self.assertEqual(datastr,'1.44:0.25:25.0:1.0:1.0:1.44',"Error returning field expression") |
| 469 | + |
| 470 | + |
| 471 | + renderer.setClassAttribute("value") |
| 472 | + # Equal interval calculations |
| 473 | + renderer.updateClasses(ml,renderer.EqualInterval,3) |
| 474 | + self.assertEqual( |
| 475 | + dumpRangeBreaks(renderer.ranges()), |
| 476 | + '(0.5000-2.0000,2.0000-3.5000,3.5000-5.0000,)', |
| 477 | + 'Equal interval classification not correct') |
| 478 | + |
| 479 | + # Quantile classes |
| 480 | + renderer.updateClasses(ml,renderer.Quantile,3) |
| 481 | + self.assertEqual( |
| 482 | + dumpRangeBreaks(renderer.ranges()), |
| 483 | + '(0.5000-1.0000,1.0000-1.2000,1.2000-5.0000,)', |
| 484 | + 'Quantile classification not correct') |
| 485 | + renderer.updateClasses(ml,renderer.Quantile,4) |
| 486 | + self.assertEqual( |
| 487 | + dumpRangeBreaks(renderer.ranges()), |
| 488 | + '(0.5000-1.0000,1.0000-1.1000,1.1000-1.2000,1.2000-5.0000,)', |
| 489 | + 'Quantile classification not correct') |
| 490 | + |
| 491 | + # Tests still needed |
| 492 | + |
| 493 | + # Other calculation method tests |
| 494 | + # createRenderer function |
| 495 | + # symbolForFeature correctly selects range |
| 496 | + |
| 497 | +if __name__ == "__main__": |
| 498 | + unittest.main() |
0 commit comments