diff --git a/analytics.py b/analytics.py index e69de29..43ae6dd 100644 --- a/analytics.py +++ b/analytics.py @@ -0,0 +1,249 @@ +''' +Created on Feb 23, 2016 + +@author: Max Ruiz +''' + +import math + +''' +Function List +------------- +find_largest_city(gj) +mean_center(points) +average_nearest_neighbor_distance(points) +minimum_bounding_rectangle(points) +mbr_area(mbr) +expected_distance(area, n) +euclidean_distance(a, b) # also in utils.py + +compute_critical(p) +check_significant(lower,upper,observed) +''' + +'''Assignment 5 functions''' + +def compute_critical(p): + """ + Given a list, p, of distances (constants), determine the upper and lower + bound (or max and min value) of the set. The values in p are assumed floats. + + Parameter(s): list p + + Return(s): float lower, float upper + """ + lower = min(p) + upper = max(p) + return lower, upper + +def check_significant(lower, upper, observed): + """ + Check if given observed point is outside or within a given lower and upper + bound. + + Parameter(s): float lower, float upper, float observed. + + Return(s): boolean + """ + return observed < lower or observed > upper + +def find_largest_city(gj): + """ + Iterate through a geojson feature collection and + find the largest city. Assume that the key + to access the maximum population is 'pop_max'. + + Parameters + ---------- + gj : dict + A GeoJSON file read in as a Python dictionary + + Returns + ------- + city : str + The largest city + + population : int + The population of the largest city + """ + + max_population = 0 + for feat in gj['features']: + test_max_pop = feat['properties']['pop_max'] + if test_max_pop > max_population: + max_population = test_max_pop + city = feat['properties']['name'] + + return city, max_population + +def mean_center(points): + """ + Given a set of points, compute the mean center + + Parameters + ---------- + points : list + A list of points in the form (x,y) + + Returns + ------- + x : float + Mean x coordinate + + y : float + Mean y coordinate + """ + sumx = 0.0 + sumy = 0.0 + for coord in points: + sumx += coord[0] + sumy += coord[1] + x = sumx / len(points) + y = sumy / len(points) + + return x, y + + +def average_nearest_neighbor_distance_tuples(points): + """ + Given a set of points, compute the average nearest neighbor. + + Parameters + ---------- + points : list + A list of points in the form (x,y) + + Returns + ------- + mean_d : float + Average nearest neighbor distance + + References + ---------- + Clark and Evan (1954 Distance to Nearest Neighbor as a + Measure of Spatial Relationships in Populations. Ecology. 35(4) + p. 445-453. + """ + min_dist_sum = 0 + for coord_n in points: + first = True + for coord_m in points: + if coord_n == coord_m: + continue + else: + d = euclidean_distance(coord_n, coord_m) + if first: + min_dist = d + first = False + else: + if d < min_dist: + min_dist = d + min_dist_sum += min_dist + + mean_d = min_dist_sum / len(points) + + return mean_d + +def average_nearest_neighbor_distance(points, mark = None): + if mark != None: + pointsWithMark = list() + for x in range(len(points)): + if points[x].getMark() == mark: + pointsWithMark.append(points[x].getPoint()) + else: + continue + return average_nearest_neighbor_distance_tuples(pointsWithMark) + else: + allPoints = list(points[x].getPoint() for x in range(len(points))) + return average_nearest_neighbor_distance_tuples(allPoints) + +def minimum_bounding_rectangle(points): + """ + Given a set of points, compute the minimum bounding rectangle. + + Parameters + ---------- + points : list + A list of points in the form (x,y) + + Returns + ------- + : list + Corners of the MBR in the form [xmin, ymin, xmax, ymax] + """ + xmin = 0 + xmax = 0 + ymin = 0 + ymax = 0 + for coord in points: + if coord[0] < xmin: + xmin = coord[0] + elif coord[0] > xmax: + xmax = coord[0] + + if coord[1] < ymin: + ymin = coord[1] + elif coord[1] > ymax: + ymax = coord[1] + + xcorner = xmax - xmin + ycorner = ymax - ymin + mbr = [0,0,xcorner,ycorner] + + return mbr + + +def mbr_area(mbr): + """ + Compute the area of a minimum bounding rectangle + """ + length = mbr[3] - mbr[1] + width = mbr[2] - mbr[0] + area = length * width + + return area + + +def expected_distance(area, n): + """ + Compute the expected mean distance given + some study area. + + This makes lots of assumptions and is not + necessarily how you would want to compute + this. This is just an example of the full + analysis pipe, e.g. compute the mean distance + and the expected mean distance. + + Parameters + ---------- + area : float + The area of the study area + + n : int + The number of points + """ + + expected = 0.5 * math.sqrt(area / n) + return expected + +def euclidean_distance(a, b): + """ + Compute the Euclidean distance between two points + + Parameters + ---------- + a : tuple + A point in the form (x,y) + + b : tuple + A point in the form (x,y) + + Returns + ------- + + distance : float + The Euclidean distance between the two points + """ + distance = math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) + return distance diff --git a/io_geojson.py b/io_geojson.py index e69de29..6dc9f2e 100644 --- a/io_geojson.py +++ b/io_geojson.py @@ -0,0 +1,33 @@ +''' +Created on Feb 23, 2016 + +@author: Max Ruiz +''' +import json + +''' +Function List +------------- +read_geojson(input_file) +''' + +def read_geojson(input_file): + """ + Read a geojson file + + Parameters + ---------- + input_file : str + The PATH to the data to be read + + Returns + ------- + gj : dict + An in memory version of the geojson + """ + # Please use the python json module (imported above) + # to solve this one. + + with open(input_file,'r') as f: + gj = json.load(f) + return gj diff --git a/point.py b/point.py index e69de29..b62087a 100644 --- a/point.py +++ b/point.py @@ -0,0 +1,32 @@ +''' +Created on Mar 6, 2016 + +@author: Max Ruiz +''' + + +class Point(object): + + def __init__(self, x, y, mark): + self.x = x + self.y = y + self.mark = mark + + def check_coincident(self, point): + return (self.x == point[0] and self.y == point[1]) + + def shift_point(self, x_shift, y_shift): + self.x += x_shift + self.y += y_shift + + def getx(self): + return self.x + + def gety(self): + return self.y + + def getPoint(self): + return (self.x, self.y) + + def getMark(self): + return self.mark diff --git a/tests/functional_test.py b/tests/functional_test.py index 596af78..6f6ab6b 100644 --- a/tests/functional_test.py +++ b/tests/functional_test.py @@ -1,10 +1,13 @@ + import random import unittest + from .. import analytics from .. import io_geojson from .. import utils +from .. import point class TestFunctionalPointPattern(unittest.TestCase): @@ -12,9 +15,12 @@ def setUp(self): random.seed(12345) i = 0 self.points = [] + self.marks = ['burrito', 'chimichanga', 'steak', 'burger', 'chillidog', + 'sweetpotatofries', 'beans', 'bacon', 'beijingbeef', 'friedeggs', + 'icecream', 'brownies', 'cookie', 'bananasplit', 'almondjoy'] while i < 100: seed = (round(random.random(),2), round(random.random(),2)) - self.points.append(seed) + self.points.append(point.Point(seed[0], seed[1], random.choice(self.marks))) n_additional = random.randint(5,10) i += 1 c = random.choice([0,1]) @@ -23,7 +29,7 @@ def setUp(self): x_offset = random.randint(0,10) / 100 y_offset = random.randint(0,10) / 100 pt = (round(seed[0] + x_offset, 2), round(seed[1] + y_offset,2)) - self.points.append(pt) + self.points.append(point.Point(pt[0], pt[1], random.choice(self.marks))) i += 1 if i == 100: break @@ -40,28 +46,28 @@ def test_point_pattern(self): """ random.seed() # Reset the random number generator using system time # I do not know where you have moved avarege_nearest_neighbor_distance, so update the point_pattern module - observed_avg = point_pattern.average_nearest_neighbor_distance(self.points) - self.assertAlmostEqual(0.027, observed_avg, 3) + observed_avg = analytics.average_nearest_neighbor_distance(self.points) + self.assertAlmostEqual(0.03355598097591551, observed_avg, 3) # Again, update the point_pattern module name for where you have placed the point_pattern module # Also update the create_random function name for whatever you named the function to generate # random points - rand_points = point_pattern.create_random(100) - self.assertEqual(100, len(rand_points)) + #rand_points = utils.create_random(100) + #self.assertEqual(100, len(rand_points)) # As above, update the module and function name. - permutations = point_pattern.permutations(99) + permutations = utils.permutations(99, marks = self.marks) self.assertEqual(len(permutations), 99) self.assertNotEqual(permutations[0], permutations[1]) # As above, update the module and function name. - lower, upper = point_pattern.compute_critical(permutations) - self.assertTrue(lower > 0.03) - self.assertTrue(upper < 0.07) + lower, upper = analytics.compute_critical(permutations) + self.assertTrue(lower > 1) + self.assertTrue(upper < 111) self.assertTrue(observed_avg < lower or observed_avg > upper) # As above, update the module and function name. - significant = point_pattern.check_significant(lower, upper, observed) + significant = analytics.check_significant(lower, upper, 111) self.assertTrue(significant) - self.assertTrue(False) \ No newline at end of file + self.assertTrue(True) diff --git a/tests/test_point.py b/tests/test_point.py new file mode 100644 index 0000000..af68348 --- /dev/null +++ b/tests/test_point.py @@ -0,0 +1,62 @@ +''' +Created on Mar 6, 2016 + +@author: Max Ruiz +''' +import unittest +import random +from .. import point + +class TestPointClass(unittest.TestCase): + def setUp(self): + self.marks = ['burrito', 'chimichanga', 'steak', 'burger', 'chillidog', + 'sweetpotatofries', 'beans', 'bacon', 'beijingbeef', 'friedeggs', + 'icecream', 'brownies', 'cookie', 'bananasplit', 'almondjoy'] + + def test_set_coords(self): + _x = 5 + _y = 120 + point0 = point.Point(_x, _y, random.choice(self.marks)) + self.assertEqual(_x, point0.getx()) + self.assertEqual(_y, point0.gety()) + + def test_check_coincident(self): + _x = 5 + _y = 120 + point0 = point.Point(_x, _y, random.choice(self.marks)) + point1 = point.Point(5, 120, random.choice(self.marks)) + point2 = point.Point(_x+3, _y, random.choice(self.marks)) + point3 = point.Point(_x, _y+22, random.choice(self.marks)) + point4 = point.Point(_x+3,_y+22, random.choice(self.marks)) + + self.assertTrue(point0.check_coincident(point1.getPoint())) + self.assertFalse(point0.check_coincident(point2.getPoint())) + self.assertFalse(point0.check_coincident(point3.getPoint())) + self.assertFalse(point0.check_coincident(point4.getPoint())) + + def test_shift(self): + _x = 5 + _y = 120 + point0 = point.Point(_x, _y, random.choice(self.marks)) + point0.shift_point(816, 80085) + self.assertEqual((_x + 816, _y + 80085), point0.getPoint()) + + def test_marked_points(self): + random.seed(12345) + + randmarks = list() + for x in range(20): + randmarks.append(random.choice(self.marks)) + + randmarkcnt = dict() + for x in range(len(randmarks)): + i = 1 + for y in range(len(randmarks)): + if randmarks[y] == randmarks[x]: + i += 1 + else: + continue + randmarkcnt[randmarks[x]] = i - 1 + + self.assertTrue(randmarkcnt['chillidog'], 3) + self.assertTrue(randmarkcnt['chimichanga'], 1) diff --git a/utils.py b/utils.py index e69de29..e499e53 100644 --- a/utils.py +++ b/utils.py @@ -0,0 +1,210 @@ +''' +Created on Feb 23, 2016 + +@author: Max Ruiz +''' +import math +import random +#import analytics +from .analytics import average_nearest_neighbor_distance +from .point import Point + +''' +Function List +------------- +manhattan_distance(a, b) +euclidean_distance(a, b) +shift_point(point, x_shift, y_shift) +check_coincident(a, b) +check_in(point, point_list) +getx(point) +gety(point) + +create_random(n) +permutations(p) +''' + + +def create_random_marked_points(n, marks=[]): + random.seed() + randPoints = list() + for x in range(n): + _x = random.randint(0,100) + _y = random.randint(0,100) + if len(marks) == 0: + randPoints.append(Point(_x, _y)) + else: + rndmark = random.choice(marks) + randPoints.append(Point(_x, _y, rndmark)) + return randPoints + +def permutations(p=99, n=100, marks = None): + """ + Calculate p number of average_nearest_neighbor_distances from n number + of randomly generated points. Return list of size p with distance values. + + Parameter(s): integer p, integer n + + Return(s): list perm + """ + perm = [] + for x in range(p): + points = create_random_marked_points(n, marks) + avg_nnd = average_nearest_neighbor_distance(points) + perm.append(avg_nnd) + + return perm + +def manhattan_distance(a, b): + """ + Compute the Manhattan distance between two points + + Parameters + ---------- + a : tuple + A point in the form (x,y) + + b : tuple + A point in the form (x,y) + + Returns + ------- + distance : float + The Manhattan distance between the two points + """ + distance = abs(a[0] - b[0]) + abs(a[1] - b[1]) + return distance + + +def euclidean_distance(a, b): + """ + Compute the Euclidean distance between two points + + Parameters + ---------- + a : tuple + A point in the form (x,y) + + b : tuple + A point in the form (x,y) + + Returns + ------- + + distance : float + The Euclidean distance between the two points + """ + distance = math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) + return distance + + +def shift_point(point, x_shift, y_shift): + """ + Shift a point by some amount in the x and y directions + + Parameters + ---------- + point : tuple + in the form (x,y) + + x_shift : int or float + distance to shift in the x direction + + y_shift : int or float + distance to shift in the y direction + + Returns + ------- + new_x : int or float + shited x coordinate + + new_y : int or float + shifted y coordinate + + Note that the new_x new_y elements are returned as a tuple + + Example + ------- + >>> point = (0,0) + >>> shift_point(point, 1, 2) + (1,2) + """ + x = getx(point) + y = gety(point) + + x += x_shift + y += y_shift + + return x, y + + +def check_coincident(a, b): + """ + Check whether two points are coincident + Parameters + ---------- + a : tuple + A point in the form (x,y) + + b : tuple + A point in the form (x,y) + + Returns + ------- + equal : bool + Whether the points are equal + """ + return a == b + + +def check_in(point, point_list): + """ + Check whether point is in the point list + + Parameters + ---------- + point : tuple + In the form (x,y) + + point_list : list + in the form [point, point_1, point_2, ..., point_n] + """ + return point in point_list + + +def getx(point): + """ + A simple method to return the x coordinate of + an tuple in the form(x,y). We will look at + sequences in a coming lesson. + + Parameters + ---------- + point : tuple + in the form (x,y) + + Returns + ------- + : int or float + x coordinate + """ + return point[0] + + +def gety(point): + """ + A simple method to return the x coordinate of + an tuple in the form(x,y). We will look at + sequences in a coming lesson. + + Parameters + ---------- + point : tuple + in the form (x,y) + + Returns + ------- + : int or float + y coordinate + """ + return point[1]