From f6b26952ca47d6a3740ef244ce030e08be56679f Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 12 Sep 2009 10:55:14 -0400 Subject: [PATCH] Added state, county, and tract fields to the Block class. Renamed the other Block attributes to follow the GeoRecord/Tiger naming convention. Updated any tests/methods that depended on the Block attribute names. Throw an error from within the Block class if the "block" attribute is non-integral. --- src/SummaryFile1.py | 66 +++++++++++++++++++++++------- src/Tests/Unit/SummaryFile1Test.py | 5 ++- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/SummaryFile1.py b/src/SummaryFile1.py index 0ad410d..bfc6258 100644 --- a/src/SummaryFile1.py +++ b/src/SummaryFile1.py @@ -17,36 +17,71 @@ class GeoRecord: class Block: """ - Represents a block (which is a special case of a GeoRecord. - All we care about here is the block number, population, - area, and coordinates. + Represents a block (which is a special case of a GeoRecord). + There are some convenience methods tacked on to make computation + and querying easier. """ def __init__(self, geo_record): - """We initialize from a GeoRecord object""" + """ + We initialize from a GeoRecord object. It is important that + we raise some kind of error if there is no 'block' field, since + that means we weren't passed a block. + """ + if not (StringUtils.is_integer(geo_record.block)): + raise RecordError('GeoRecord object does not represent a block.') + + # These need to be stored as strings so they don't + # affect the block_identifier() generation. + self.state = geo_record.state + self.county = geo_record.county + self.tract = geo_record.tract + self.block = geo_record.block + # All of these int/float conversions will throw a ValueError # if the input string cannot be converted o the specified # type. - self.block_number = int(geo_record.block) - self.tract_number = int(geo_record.tract) - self.population = int(geo_record.pop100) - self.area_land = float(geo_record.arealand) - self.area_water = float(geo_record.areawatr) + self.pop100 = int(geo_record.pop100) + self.arealand = float(geo_record.arealand) + self.areawatr = float(geo_record.areawatr) self.coordinates = GPS.Coordinates() self.coordinates.latitude = float(geo_record.intptlat) self.coordinates.longitude = float(geo_record.intptlon) - if (self.total_area() == 0): - raise InvalidAreaError('A block may not have zero area.') - + + def tiger_blkidfp00(self): + # From the Tiger/Line shapefile documentation: + # + # Current block identifier; a concatenation of Census 2000 + # state FIPS code, Census 2000 county FIPS code, Census + # BLKIDFP 16 String 2000 census tract code, Census 2000 + # tabulation block number, and current block suffix 1. + # + return (self.state + + self.county + + self.tract + + self.block) + def total_area(self): - return (self.area_land + self.area_water) + return (self.arealand + self.areawatr) def population_density(self): - return (self.population / self.total_area()) + # There are some unusual cases where a block will have a + # total area of zero. It also seems that these unusual blocks + # do in fact posess geometries, provided in the Tiger database. + # Therefore, we allow them to be parsed. + # + # The choice to assign these blocks an average density of 0 + # was arbitrary. + # + if (self.total_area() == 0): + return 0 + else: + return (self.pop100 / self.total_area()) + class GeoRecordParser: @@ -81,6 +116,9 @@ class GeoRecordParser: try: block = Block(record) blocks.append(block) + except RecordError: + # Ain't a block. + continue except ValueError: # A value couldn't be converted to the appropriate type. continue diff --git a/src/Tests/Unit/SummaryFile1Test.py b/src/Tests/Unit/SummaryFile1Test.py index a29e208..edaf598 100644 --- a/src/Tests/Unit/SummaryFile1Test.py +++ b/src/Tests/Unit/SummaryFile1Test.py @@ -12,6 +12,9 @@ class BlockTest(unittest.TestCase): # Fill a GeoRecord with dummy values so that we # can calculate its average population density. gr = SummaryFile1.GeoRecord() + gr.state = '24' + gr.county = '001' + gr.tract = '123456' gr.block = '1728' gr.pop100 = '100' gr.arealand = '40' @@ -80,7 +83,7 @@ class SummaryFile1Test(unittest.TestCase): b_coords.longitude = b.coordinates.longitude closest_block = SummaryFile1.FindClosestBlock(blocks, b_coords) - self.assertEqual(b.block_number, closest_block.block_number) + self.assertEqual(b.block, closest_block.block) def testEachBlockHasItsOwnAverageDensity(self): -- 2.44.2