diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..fc39761 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +assignment_06 \ No newline at end of file diff --git a/.idea/assignment_06.iml b/.idea/assignment_06.iml new file mode 100644 index 0000000..17a66b8 --- /dev/null +++ b/.idea/assignment_06.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f9edad6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ecf6f2d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..1575117 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,575 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1457978272577 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__pycache__/__init__.cpython-35.pyc b/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000..085b987 Binary files /dev/null and b/__pycache__/__init__.cpython-35.pyc differ diff --git a/__pycache__/analytics.cpython-35.pyc b/__pycache__/analytics.cpython-35.pyc new file mode 100644 index 0000000..b8adbd2 Binary files /dev/null and b/__pycache__/analytics.cpython-35.pyc differ diff --git a/__pycache__/io_geojson.cpython-35.pyc b/__pycache__/io_geojson.cpython-35.pyc new file mode 100644 index 0000000..0d13cf1 Binary files /dev/null and b/__pycache__/io_geojson.cpython-35.pyc differ diff --git a/__pycache__/point.cpython-35.pyc b/__pycache__/point.cpython-35.pyc new file mode 100644 index 0000000..127e54b Binary files /dev/null and b/__pycache__/point.cpython-35.pyc differ diff --git a/analytics.py b/analytics.py index e69de29..46bfe7e 100644 --- a/analytics.py +++ b/analytics.py @@ -0,0 +1,278 @@ +import math # For all of the math used +# import utils + +from utils import generate_rand_points +# ------------------------------------------------------------------ +# +# Joseph Cruz +# analytics.py +# +# Stores the functions from point_pattern.py that perform analysis +# on data. +# ------------------------------------------------------------------ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# function mean_nearest_neighbors_randomPoints +# +# Determines the mean nearest neighbor of randomly generated points +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +def permutations(p = 99, n = 100): + list_means = [] + + for i in range(p): + # randPoints = utils.generate_rand_points(n) + rand_points = generate_rand_points(n) + newMean = average_nearest_neighbor_distance(rand_points) + list_means.append(newMean) + + return list_means + +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# function find_crit_points +# +# Finds the critical points (min and max) of a list +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +def find_crit_points(list_means): + entries = list_means + maxEntry = 0 + minEntry = 2 + for i in range(len(list_means)): + if entries[i] > maxEntry: + maxEntry = entries[i] + if entries[i] < minEntry: + minEntry = entries[i] + + return minEntry,maxEntry + +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# function crit_point_check +# +# Checks if the observed value is within the range of the min and max +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + +def crit_point_check(minEntry, maxEntry, observed): + if observed < minEntry or observed > maxEntry: + return True + else: + return False + + +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 + """ + x = 0 + y = 0 + numOfPoints = len(points) + + for i in range(numOfPoints): + x = x + points[i][0] + y = y + points[i][1] + + x = x/numOfPoints + y = y/numOfPoints + + return x, y + +def average_nearest_neighbor_distance(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. + """ + mean_d = 0 + total = 0 + local_nn = 0 + numOfPoints = len(points) + + for i in range(numOfPoints): + local_nn = 0 #reset local_nn for the new point + for j in range(numOfPoints): + if i != j: + newDistance = euclidean_distance(points[i],points[j]) + if local_nn == 0: + local_nn = newDistance + elif newDistance < local_nn: + local_nn = newDistance + + total = total + local_nn + + mean_d = total/numOfPoints + + + return mean_d + + +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] + """ + mbr = [0,0,0,0] + numOfPoints = len(points) + for i in range(numOfPoints): + #Check for min and max x + if points[i][0] < mbr[0]: + mbr[0] = points[i][0] + if points[i][0] > mbr[2]: + mbr[2] = points[i][0] + #Check for min and max y + if points[i][1] < mbr[1]: + mbr[1] = points[i][1] + if points[i][1] > mbr[3]: + mbr[3] = points[i][1] + + return mbr + + +def mbr_area(mbr): + """ + Compute the area of a minimum bounding rectangle + """ + area = (mbr[2] - mbr[0])*(mbr[3] - mbr[1]) + + 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 = (1/2)*math.sqrt(area/n) + return expected + +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 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 + diff --git a/io_geojson.py b/io_geojson.py index e69de29..4e945c5 100644 --- a/io_geojson.py +++ b/io_geojson.py @@ -0,0 +1,83 @@ +import json #for the geojson stuff + +#------------------------------------------------------------------ +# +# Joseph Cruz +# io_geojson.py +# +# Stores the functions from point_pattern.py that are a form of u- +# tility needed for use in other functions +#------------------------------------------------------------------ + +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) as iFile: + gj = json.load(iFile) + return gj + + +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 + """ + gj_features = gj['features'] + city = None + max_population = 0 + + for nextFeature in gj_features: + if nextFeature['pop_max'] > max_population: + city = nextFeature['name'] + max_population = nextFeature['pop_max'] + + return city, max_population + + +def write_your_own(gj): + """ + Here you will write your own code to find + some attribute in the supplied geojson file. + + Take a look at the attributes available and pick + something interesting that you might like to find + or summarize. This is totally up to you. + + Do not forget to write the accompanying test in + tests.py! + """ + #Counts the number of world cities + gj_features = gj['features'] + numWorldCities = 0 + + for nextFeature in gj_features: + if nextFeature['worldcity'] != 0: + numWorldCities += 1 + return numWorldCities diff --git a/point.py b/point.py index e69de29..fb6ba23 100644 --- a/point.py +++ b/point.py @@ -0,0 +1,108 @@ +import random +import math + + +class Point: + """ + For whatever reason, cannot get import to work, just moved functionality + into this file instead. + """ + def __init__(self,x = 0,y = 0,mark = ""): + self.x = x + self.y = y + self.mark = mark + + def shift_point(self,x_move,y_move): + this_point = (self.x,self.y) + self.x += x_move + self.y += y_move + + def coincident(self, check_point): + if check_point.x == self.x and check_point.y == self.y: + return True + else: + return False + + +def create_random_marked_points(n, marks = []): + list_of_tuples = [(random.uniform(0,1), random.uniform(0,1)) for i in range(n)] + list_of_marks = [random.choice(marks) for i in range(n)] + list_of_points = [] + for j in range(n): + new_point = Point(list_of_tuples[j][0],list_of_tuples[j][1],list_of_marks[j]) + list_of_points.append(new_point) + + return list_of_points + + +def euclidean_distance(a, b): + distance = math.sqrt((a.x - b.x)**2 + (a.y - b.y)**2) + return distance + + +def average_nearest_neighbor_distance(points, mark=""): + mean_d = 0 + total = 0 + local_nn = 0 + num_of_points = len(points) + + if not mark: + for i in range(num_of_points): + local_nn = 0 + for j in range(num_of_points): + if i != j: + new_distance = euclidean_distance(points[i],points[j]) + if local_nn == 0: + local_nn = new_distance + elif new_distance < local_nn: + local_nn = new_distance + + total += local_nn + + else: + for i in range(num_of_points): + local_nn = 0 + for j in range(num_of_points): + if i != j and points[i].mark == points[j].mark: + new_distance = euclidean_distance(points[i],points[j]) + if local_nn == 0: + local_nn = new_distance + elif new_distance < local_nn: + local_nn = new_distance + + total += local_nn + + mean_d = total/num_of_points + return mean_d + + +def permutations(p = 99, n = 100): + list_means = [] + + for i in range(p): + marks = ["elf", "dwarf", "human", "orc"] + rand_points = create_random_marked_points(n, marks) + newMean = average_nearest_neighbor_distance(rand_points) + list_means.append(newMean) + + return list_means + + +def find_crit_points(list_means): + entries = list_means + maxEntry = 0 + minEntry = 2 + for i in range(len(list_means)): + if entries[i] > maxEntry: + maxEntry = entries[i] + if entries[i] < minEntry: + minEntry = entries[i] + + return minEntry,maxEntry + + +def crit_point_check(minEntry, maxEntry, observed): + if observed < minEntry or observed > maxEntry: + return True + else: + return False \ No newline at end of file diff --git a/tests/__pycache__/__init__.cpython-35.pyc b/tests/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000..d46027b Binary files /dev/null and b/tests/__pycache__/__init__.cpython-35.pyc differ diff --git a/tests/__pycache__/functional_test.cpython-35.pyc b/tests/__pycache__/functional_test.cpython-35.pyc new file mode 100644 index 0000000..9b183fa Binary files /dev/null and b/tests/__pycache__/functional_test.cpython-35.pyc differ diff --git a/tests/__pycache__/point_test.cpython-35.pyc b/tests/__pycache__/point_test.cpython-35.pyc new file mode 100644 index 0000000..b1c218c Binary files /dev/null and b/tests/__pycache__/point_test.cpython-35.pyc differ diff --git a/tests/functional_test.py b/tests/functional_test.py index 596af78..ba33050 100644 --- a/tests/functional_test.py +++ b/tests/functional_test.py @@ -1,9 +1,8 @@ import random import unittest -from .. import analytics from .. import io_geojson -from .. import utils +from .. import point class TestFunctionalPointPattern(unittest.TestCase): @@ -11,9 +10,14 @@ class TestFunctionalPointPattern(unittest.TestCase): def setUp(self): random.seed(12345) i = 0 + marks = ["elf", "dwarf", "human", "orc"] + rand_marks = [] + for i in range(100): + rand_marks.append(random.choice(marks)) + self.points = [] while i < 100: - seed = (round(random.random(),2), round(random.random(),2)) + seed = point.Point(round(random.random(),2), round(random.random(),2), rand_marks[i]) self.points.append(seed) n_additional = random.randint(5,10) i += 1 @@ -22,7 +26,7 @@ def setUp(self): for j in range(n_additional): 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)) + pt = point.Point(round(seed.x + x_offset, 2), round(seed.y + y_offset,2), random.choice(marks)) self.points.append(pt) i += 1 if i == 100: @@ -38,30 +42,35 @@ def test_point_pattern(self): nearest neighbor distance computed using a random realization of the point process. """ + marks = ["elf", "dwarf", "human", "orc"] 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_elf = point.average_nearest_neighbor_distance(self.points,"elf") + self.assertAlmostEqual( 0.02555, observed_avg_elf, 3) + observed_avg_dwarf = point.average_nearest_neighbor_distance(self.points,"dwarf") + self.assertAlmostEqual( 0.02555, observed_avg_dwarf, 3) + observed_avg_human = point.average_nearest_neighbor_distance(self.points,"human") + self.assertAlmostEqual( 0.02555, observed_avg_human, 3) + observed_avg_orc = point.average_nearest_neighbor_distance(self.points,"orc") + self.assertAlmostEqual( 0.02555, observed_avg_orc, 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) + rand_points = point.create_random_marked_points(100,marks) self.assertEqual(100, len(rand_points)) # As above, update the module and function name. - permutations = point_pattern.permutations(99) + permutations = point.permutations(99) 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) + lower, upper = point.find_crit_points(permutations) self.assertTrue(lower > 0.03) self.assertTrue(upper < 0.07) - self.assertTrue(observed_avg < lower or observed_avg > upper) + self.assertTrue(observed_avg_elf < lower or observed_avg_elf > upper) # As above, update the module and function name. - significant = point_pattern.check_significant(lower, upper, observed) + significant = point.crit_point_check(lower, upper, observed_avg_elf) self.assertTrue(significant) - self.assertTrue(False) \ No newline at end of file diff --git a/tests/point_test.py b/tests/point_test.py new file mode 100644 index 0000000..454b963 --- /dev/null +++ b/tests/point_test.py @@ -0,0 +1,71 @@ +from .. import point +import unittest +import random + + +class TestPointClass(unittest.TestCase): + + def set_up(self): + pass + + def test_point_pattern(self): + random.seed(12345) + rand_tuple = (random.randint(0,10),random.randint(0,10)) + check_point = point.Point(rand_tuple[0],rand_tuple[1],"some mark") + """ Tests that the point is being set correctly """ + self.assertEqual(check_point.x, 6) + self.assertEqual(check_point.y, 0) + + """ Tests to insure coincidence is read properly """ + rand_tuple2 = (random.randint(0,10),random.randint(0,10)) + copy_point = point.Point(6,0,"balrog") + check_point2 = point.Point(rand_tuple2[0],rand_tuple2[1],"some other mark") + self.assertTrue(check_point.coincident(copy_point)) + self.assertFalse(check_point.coincident(check_point2)) + + """ Tests for shift_point """ + pos_shift_point = point.Point(rand_tuple[0],rand_tuple[1],"some mark") + neg_shift_point = point.Point(rand_tuple[0],rand_tuple[1],"some mark") + + pos_shift_point.shift_point(rand_tuple2[0],rand_tuple2[1]) + self.assertTrue(pos_shift_point.x == 10 and pos_shift_point.y == 5) + + neg_shift_point.shift_point(-rand_tuple2[0],-rand_tuple2[1]) + self.assertTrue(neg_shift_point.x == 2 and neg_shift_point.y == -5) + + def test_marks(self): + list_of_points = [] + marks = ["elf", "dwarf", "human", "orc"] + random.seed(12345) + list_of_points = point.create_random_marked_points(20,marks) + + elf_counter = 0 + human_counter = 0 + dwarf_counter = 0 + orc_counter = 0 + + for i in range(len(list_of_points)): + if list_of_points[i].mark == "elf": + elf_counter += 1 + elif list_of_points[i].mark == "human": + human_counter += 1 + elif list_of_points[i].mark == "dwarf": + dwarf_counter += 1 + elif list_of_points[i].mark == "orc": + orc_counter += 1 + + self.assertEqual(elf_counter, 4) + self.assertEqual(human_counter, 5) + self.assertEqual(dwarf_counter, 8) + self.assertEqual(orc_counter, 3) + + def test_nearest_neightbor(self): + random.seed(12345) + marks = ["elf", "dwarf", "human", "orc"] + list_of_points = point.create_random_marked_points(20,marks) + + distance_no_mark = point.average_nearest_neighbor_distance(list_of_points) + distance_with_mark = point.average_nearest_neighbor_distance(list_of_points,"orc") + + self.assertAlmostEqual(distance_no_mark, 0.13861788961152158, 5) + self.assertAlmostEqual(distance_with_mark, 0.253406515134334, 5) \ No newline at end of file diff --git a/utils.py b/utils.py index e69de29..51adb31 100644 --- a/utils.py +++ b/utils.py @@ -0,0 +1,99 @@ +import math #For all of the math used +import random # For random used +# ------------------------------------------------------------------ +# +# Joseph Cruz +# utils.py +# +# Stores the functions from point_pattern.py that are a form of +# utility needed for use in other functions +# ------------------------------------------------------------------ + +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# function generate_rand_points() +# +# Generates an integer number of random points based on user input +# Points will be within the domain [0,1] +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +def generate_rand_points(n): + rng = random.Random() + listofPoints = [(random.uniform(0,1), random.uniform(0,1)) for i in range(n)] + + return listofPoints + +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 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]