]> gitweb.michael.orlitzky.com - dead/census-tools.git/blob - src/Census.py
63f69aaccaadf355b7d1b82414841e1d2839111b
[dead/census-tools.git] / src / Census.py
1 import pgdb
2
3 import Configuration.Defaults
4 import GPS
5 import SummaryFile1
6
7
8 class Database:
9 """
10 This class wraps all of the operations that we'd like to perform
11 on the census database. Most of the utility scripts will just call
12 one or two methods from within this class.
13 """
14
15 def __init__(self,
16 initial_host=Configuration.Defaults.DATABASE_HOST,
17 initial_database=Configuration.Defaults.DATABASE_NAME,
18 initial_username=Configuration.Defaults.DATABASE_USERNAME,
19 initial_srid=Configuration.Defaults.SRID):
20
21 self.connection = pgdb.connect(host=initial_host,
22 database=initial_database,
23 user=initial_username)
24 self.srid = initial_srid
25
26
27 def __del__(self):
28 self.connection.close()
29
30
31 def find_average_population_density(self, coords):
32 """
33 Find the average population density at a set of GPS coordinates.
34 """
35 cursor = self.connection.cursor()
36
37 query = """
38 SELECT population_density
39 FROM (sf1_blocks INNER JOIN tiger_blocks
40 ON sf1_blocks.blkidfp00=tiger_blocks.blkidfp00)
41 WHERE ST_Contains(tiger_blocks.the_geom,
42 ST_SetSRID(ST_Point(%.6f, %.6f), %d));
43 """
44
45 sql_params = (coords.longitude, coords.latitude, self.srid)
46 cursor.execute(query, sql_params)
47 rows = cursor.fetchall()
48 cursor.close()
49
50 if len(rows) > 0:
51 return rows[0][0]
52 else:
53 return None
54
55
56 def find_contained_population(self, well_known_text):
57 """
58 Find the population contained within a geometric object,
59 given in OGC Well-Known Text format.
60 """
61 cursor = self.connection.cursor()
62
63 # We're ready to build our query, one step at a time. Firsy, we store
64 # the Text->Geom conversion in a variable; this just makes the query a
65 # little easier to read.
66 geometric_object = "ST_GeomFromText(%s, %d)"
67
68 # We want to compute the population "under" the geometric object. We
69 # can compute the percentage of a block that is covered by taking the
70 # area of (the intersection of the object and the block) divided by
71 # the total area of the block.
72 #
73 # Once we know the percentage covered, we just multiply that value by
74 # the total population in the block to find the population that is
75 # covered. The sum of these values over all blocks is our final
76 # result.
77 #
78 query = """
79 SELECT SUM(sf1_blocks.pop100 *
80 ( ST_Area(ST_Intersection(%s, tiger_blocks.the_geom))
81 / ST_Area(tiger_blocks.the_geom) )
82 ) AS covered_population
83 """ % geometric_object
84 sql_params = (well_known_text, self.srid)
85
86
87 # Join our two block tables, so that we have both the demographic
88 # and geometric data.
89 query += """
90 FROM (sf1_blocks INNER JOIN tiger_blocks
91 ON sf1_blocks.blkidfp00 = tiger_blocks.blkidfp00)
92 """
93
94
95 # We only need to calculate the covered population for the blocks
96 # that actually intersect our object.
97 query += """
98 WHERE (ST_Intersects(%s, tiger_blocks.the_geom))
99 """ % geometric_object
100 # geometric_object hasn't been substituted yet, so we need
101 # to add the sql_params twice.
102 sql_params += sql_params
103
104
105 # And we only take the first result, since they're all going to be the
106 # same (our query returns the sum once for each block).
107 query += """
108 LIMIT 1
109 """
110
111 cursor.execute(query, sql_params)
112 rows = cursor.fetchall()
113 cursor.close()
114
115 if (len(rows) > 0):
116 return rows[0][0]
117 else:
118 return None
119
120
121
122 def get_block_geometry_as_wkt(self, blkidfp00):
123 """
124 Find the geometry of a (uniquely-identified) block, in
125 Well-Known Text format.
126 """
127 cursor = self.connection.cursor()
128
129 query = """
130 SELECT ST_AsText(tiger_blocks.the_geom)
131 FROM tiger_blocks
132 WHERE tiger_blocks.blkidfp00 = %s;
133 """
134 sql_params = (blkidfp00,)
135
136 cursor.execute(query, sql_params)
137 rows = cursor.fetchall()
138 cursor.close()
139
140 if len(rows) > 0:
141 return rows[0][0]
142 else:
143 return None
144