def get_shapes(self, max_area, max_distance_meters): "return the shapes [census tracts] that touch the center of max_area + max_distance" query = { 'geometry': { '$near': SON([('$geometry', SON([('type', 'Point'), ('coordinates', [longitude, latitude])])), ('$maxDistance', max_distance_meters)]) } } for shp in self.db.GENZ2010_140.find(query): # add population to properties p = shp['properties'] # for later use p['label'] = "{} {} [{}]".format( state_name(p['STATE']), county_name(p['STATE'], p['COUNTY']), p['TRACT']) pop = {} # lookup population and area raw_pop = int( self.census.sf1.state_county_tract("P0010001", p['STATE'], p['COUNTY'], p['TRACT'])[0]["P0010001"]) pop['raw'] = raw_pop #print("raw population: {}".format(raw_pop)) # compute area in our radius county_shape = shape(shp['geometry']) isect = county_shape.intersection(max_area) # save the intersection for later use. shp['intersection'] = isect pop['area'] = county_shape.area frac_contained = float(isect.area) / float(county_shape.area) pop['frac_contained'] = frac_contained #print("contained: {}".format(frac_contained)) # compute effective population #print("contained population: {}".format(frac_contained * raw_pop)) pop['effective'] = frac_contained * raw_pop p['population'] = pop # filter out areas with very low population # the mongodb geo query may be not exact if frac_contained * raw_pop < 0.1: print("WARN: clipping: {}".format(p['label'])) pprint(pop) continue yield shp
def plot_shapes(ax, shapes, filled=False, show_states=False, fc=None, alpha=0.16): # have to buffer the results to see how many colors to generate if fc == None: if filled: color_list = plt.cm.Dark2(np.linspace(0, 1, len(shapes))) fc = lambda x: color_list[x] else: fc = lambda x: 'none' states = set() geoid = {} # get the shapes covered by the coverage area. for i, shp in enumerate(shapes): p = shp['properties'] #track states we hit if p['STATE'] not in states: states.add(p['STATE']) # also store the goeid so we dont plot again later geoid[p['GEO_ID']] = shp if p['LSAD'] == 'Tract': label = "{} {} [{}]".format(state_name(p['STATE']), county_name(p['STATE'], p['COUNTY']), p['TRACT']) else: label = p['NAME'] #print ("-"*10 + label + "-"*10) #pprint(p['population']) ec = 'black' lw = 1 if 'population' in p: if p['population']['effective'] < 0.01: ec = 'blue' lw = 2 #was fc = color_list[i], patches = make_patch(shp['geometry'], fc=fc(i), lw=lw, ec=ec, label=label, alpha=alpha) for p in patches: ax.add_patch(p)
def _add_pop_to_shape_intersct(self, shp, max_area): "add the population inside the intersection of shp and max_area, shp is assumed to be a census tract." # add population to properties p = shp['properties'] #print(p) # for later use p['label'] = "{} {} [{}]".format(state_name(p['STATE']), county_name(p['STATE'], p['COUNTY']), p['TRACT']) pop = {} # lookup population and area try mongo first. searchdoc = { 'state': p["STATE"], 'county': p['COUNTY'], 'tract': p['TRACT'], 'variable.P0010001': { '$exists': True } } #print("searchdoc: ",end="") #pprint(searchdoc) cdoc = self.census_col.find_one(searchdoc) if cdoc != None: #print("Hit.") raw_pop = cdoc['variable']['P0010001'] else: raw_pop = int( self.census.sf1.state_county_tract("P0010001", p['STATE'], p['COUNTY'], p['TRACT'])[0]["P0010001"]) insdoc = { 'state': p["STATE"], 'county': p['COUNTY'], 'tract': p['TRACT'], 'variable': { 'P0010001': raw_pop } } #print("inserting: ", end="") #pprint(insdoc) self.census_col.insert_one(insdoc) pop['raw'] = raw_pop #print("raw population: {}".format(raw_pop)) county_shape = shape(shp['geometry']) if max_area != None: # compute area in our radius isect = county_shape.intersection(max_area) union = county_shape.union(max_area) # save the intersection for later use. shp['intersection'] = mapping(isect) shp['union'] = mapping(union) pop['area'] = county_shape.area frac_contained = float(isect.area) / float(county_shape.area) pop['frac_contained'] = frac_contained #print("contained: {}".format(frac_contained)) else: shp['intersection'] = shp['geometry'] shp['union'] = shp['geometry'] pop['area'] = county_shape.area frac_contained = 1.0 pop['frac_contained'] = 1.0 # compute effective population #print("contained population: {}".format(frac_contained * raw_pop)) pop['effective'] = frac_contained * raw_pop p['population'] = pop shp['properties'] = p # add area compute_land_area(shp)
# have to buffer the results to see how many colors to generate results = list(pbps.get_shapes(area, dist)) color_list = plt.cm.Dark2(np.linspace(0, 1, len(results))) # get the shapes covered by the coverage area. for i, shp in enumerate(results): p = shp['properties'] #track states we hit if p['STATE'] not in states: states.add(p['STATE']) # also store the goeid so we dont plot again later geoid[p['GEO_ID']] = shp label = "{} {} [{}]".format(state_name(p['STATE']), county_name(p['STATE'], p['COUNTY']), p['TRACT']) #print ("-"*10 + label + "-"*10) #pprint(p['population']) ec = 'black' lw = 2 if p['population']['effective'] < 0.01: ec = 'blue' lw = 4 patches = make_patch(shp['geometry'], fc=color_list[i], lw=lw, ec=ec,
def plot_single_place(outputfmt, placename, cover_by_place_q): #ps = PopulationBasedPointSampler() connection = pymongo.MongoClient( 'mongodb://*****:*****@eg-mongodb.bucknell.edu/ym015') db = connection.get_default_database() e = Elevation() # to look up point elevations. query = {'name': placename} cover_by_place = [] lossbynumbase = {} loss_threshold = {} # qfilter = {'_id':1} # if not os.path.exists(outputfmt.format(placename, i, 'elevation')): # qfilter ['shapes'] = 1 # qfilter ['points'] = 1 # have to talk out the filter for just id to comptue other values. cursor = db['POINTS'].find(query, { '_id': 1, 'LSAD': 1, 'state': 1, 'points': 1, 'shapes': 1, 'shape_ids': 1 }, no_cursor_timeout=True) #.limit(2) state = None for i, pointdoc in enumerate(cursor): state = pointdoc['state'] print("{}: {} of {}.".format(placename, i + 1, cursor.count())) lqry = {'point_docid': pointdoc['_id'], 'tx_height': 5, 'rx_height': 1} #lqry = {'point_docid': pointdoc['_id']} if not os.path.exists(outputfmt.format(placename, i, 'loss')): if i == 0: for rsltdoc in db['POINTRESULTS'].find(lqry, { 'nodes': 1, 'num_basestations': 1, 'loss_threshold': 1 }): lossbynumbase[rsltdoc['num_basestations']] = [ x['min_loss'] for x in rsltdoc['nodes'] if not math.isnan(x['min_loss']) ] loss_threshold[rsltdoc['num_basestations']] = [ rsltdoc['loss_threshold'] ] else: for rsltdoc in db['POINTRESULTS'].find(lqry, { 'nodes': 1, 'num_basestations': 1, 'loss_threshold': 1 }): lossbynumbase[rsltdoc['num_basestations']] += [ x['min_loss'] for x in rsltdoc['nodes'] if not math.isnan(x['min_loss']) ] loss_threshold[rsltdoc['num_basestations']].append( rsltdoc['loss_threshold']) #cqry = {'point_docid': pointdoc['_id'], 'tx_height': 5, 'rx_height': 1, 'num_basestations': 1} cqry = {'point_docid': pointdoc['_id'], 'num_basestations': 1} cover_by_place += [ x['connected'] for x in db['POINTRESULTS'].find(cqry, {'connected': 1}) ] #skip the rest, for now. #continue #print(lossbynumbase) #print(loss_threshold) # stats are the same, so only do it once. if i == 0: if (not os.path.exists(outputfmt.format(placename, i, 'elevation'))) or \ (not os.path.exists(outputfmt.format(placename, i, 'stats'))): fig = plt.figure(figsize=(8, 8)) ax = plt.subplot(111) if pointdoc['LSAD'] == 'County': c_shp_query = { 'properties.NAME': placename, 'properties.STATE': pointdoc['state'] } c_shp = list(db['GENZ2010_050'].find(c_shp_query)) #plot_shapes(ax, city_shp, filled= True, show_states = True, fc=lambda x:'red', alpha=0.99) plot_shapes(ax, c_shp, filled=False, show_states=True) elif pointdoc['LSAD'] == 'city': city_shp_query = { 'properties.NAME': placename, 'properties.STATE': pointdoc['state'] } city_shp = list(db['GENZ2010_160'].find(city_shp_query)) #plot_shapes(ax, city_shp, filled= True, show_states = True, fc=lambda x:'red', alpha=0.99) plot_shapes(ax, city_shp, filled=False, show_states=True) else: print( "WARN: unknown LSAD: {}, not plotting outline".format( pointdoc['LSAD'])) if 'shapes' not in pointdoc: print("getting shapes...") sqry = {'_id': {'$in': pointdoc['shape_ids']}} shapes = list(db['GENZ2010_140'].find(sqry)) else: shapes = pointdoc['shapes'] plot_shapes(ax, shapes, filled=True, show_states=True) # this is one way to do it # tract_shp = list(ps.get_tract_shapes_in_area(city_shp[0])) # plot_shapes(ax, tract_shp, filled= True, show_states = True) elev_data = [] for pt in pointdoc['points']: ax.plot(pt['coordinates'][0], pt['coordinates'][1], '.', color='black', ms=4, lw=2, alpha=0.75) elev_data.append(e.lookup(pt['coordinates'])) ax.ticklabel_format(useOffset=False, style="plain") ax.set_title("{}, {}".format(placename, state_name(state))) ax.axis('equal') plt.tight_layout() plt.savefig(outputfmt.format(placename, i, 'tracts')) plt.close(fig) # show elevation distribution fig = plt.figure(figsize=(8, 8)) ax = plt.subplot(111) ax.hist(elev_data, normed=1, fill=False, ec="black", lw=3, hatch=".") ax.set_title(placename) ax.set_xlabel('Elevation (meters)') ax.set_ylabel('Rate') ax.axis('tight') plt.savefig(outputfmt.format(placename, i, 'elevation')) plt.close(fig) print("{} has {} tracts.".format(placename, len(shapes))) areas = [ sh['properties']['area']['effective'] / (1000.0**2) for sh in shapes if 'area' in sh['properties'] ] # convert meters to KM pops = [ sh['properties']['population']['effective'] / 1000.0 for sh in shapes if 'area' in sh['properties'] ] #print (areas) #print (pops) print('total pop: ', sum(pops), 'median: ', numpy.median(pops)) print('total area: ', sum(areas), 'median: ', numpy.median(areas)) if not os.path.exists(outputfmt.format(placename, i, 'stats')): if areas != None and pops != None: fig = plt.figure(figsize=(8, 4)) ax = plt.subplot(121) ax.hist(areas, normed=0, fill=False, ec='black', lw=3, hatch='/') ax.set_title("Area") ax.set_xlabel('Square Kilometers') ax.set_ylabel('Count') ax.axis('normal') ax = plt.subplot(122) ax.set_title("Population") ax.hist(pops, normed=0, fill=False, ec='black', lw=3, hatch='x') ax.set_xlabel('Population (Thousands)') ax.set_ylabel('Count') ax.axis('normal') #ax.violinplot ([areas, pops], showmeans=False, showmedians=True) #ax.set_xticklabels(['Area', 'Population']) plt.tight_layout() plt.savefig(outputfmt.format(placename, i, 'stats')) plt.close(fig) #if not os.path.exists(outputfmt.format(placename, i, 'loss')): if 1: # show loss distribution fig = plt.figure(figsize=(8, 4)) ax = plt.subplot(111) bases = sorted(lossbynumbase.keys()) if len(bases) > 0: # print ('plot bases: ', end="") # pprint(bases) # print ('loss values: ', end="") # pprint ([lossbynumbase[bs] for bs in bases]) ax.violinplot([lossbynumbase[bs] for bs in bases], bases, showmeans=False, showmedians=True) # print('medians are: ', end="") # pprint([numpy.median(loss_threshold[i]) for i in bases]) ax.plot(bases, [numpy.median(loss_threshold[i]) for i in bases], '--', alpha=0.5, color='green', lw=2) ax.set_title("{}, {}".format(placename, state_name(state))) ax.set_xlabel('Number of basestations') ax.set_ylabel('Loss (dB)') ax.axis('tight') plt.tight_layout() plt.savefig(outputfmt.format(placename, i, 'loss')) plt.close(fig) else: print(lossbynumbase) print(bases) cover_by_place_q.put((placename, cover_by_place))