From 174503e42105e91f2d0dfc5d79e0637919af57cf Mon Sep 17 00:00:00 2001 From: AFRIKAKORPS1 Date: Wed, 4 May 2016 23:04:06 -0700 Subject: [PATCH] Added files via upload --- README.md | 52 +- analytics.py | 274 ++ io_geojson.py | 27 + map.html | 12168 ++++++++++++++++++++++++++++++++++++++++++++++ point.py | 36 + pointpattern.py | 124 + small.png | Bin 0 -> 2099 bytes tmp/map.html | 168 + tweet.png | Bin 0 -> 2229 bytes tweet.py | 13 + utils.py | 129 + view.py | 50 + view2.py | 61 + 13 files changed, 13076 insertions(+), 26 deletions(-) create mode 100644 analytics.py create mode 100644 io_geojson.py create mode 100644 map.html create mode 100644 point.py create mode 100644 pointpattern.py create mode 100644 small.png create mode 100644 tmp/map.html create mode 100644 tweet.png create mode 100644 tweet.py create mode 100644 utils.py create mode 100644 view.py create mode 100644 view2.py diff --git a/README.md b/README.md index 0976c0f..6b87545 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,26 @@ -# Week 13 Deliverables (E9) - Due 4/19/16 -For this week make sure that you have completed the following: -* Fork Assignment 10 to your own github repository. - * You can access assignment 10 [HERE](https://github.com/Geospatial-Python/assignment_10) -* Clone the repository locally -* Note that TravisCI is still turned off for this weel - -## Deliverable -1. In the `io_geojson` module write a function that ingests the twitter data and returns a dictionary. Note that you could write this from scratch or, if a suitable library exists (maybe a built-in), utilize someone else's library. -1. Create a new Tweet class or extend the existing Point class to store: - * The tweet text - * The tweet spatial information, e.g. lat/lon coordinats (be careful with how twitter ships the data (lat/lon vs. lon/lat) - * A few (3-5) other interesting tweet attributes - - Note: Here I leave it entirely to you to decide whether the Point class should be extended to include tweet information, a Tweet class should be created that inherets from the Point class, or a Tweet class should be created that contains (composition) a Point object. - * As a comment to your PR, please let me know how you implemented the Point - Tweet relationship and why. A sentene or two is plenty. -1. Ensure that the GUI that you created last week is taking the form of a class. This will ensure that you can track state more easily. See above or [here](http://zetcode.com/gui/pyqt4/firstprograms/) for an example of what I mean by, 'the form of a class' (under the heading 'An Application Icon', the `class Example()` code block). -1. Once your current GUI window is a class extend it to: - * Have a QWebView act as a the main, central widget. - * Embed a Folium map into the QWebView - * Add the tweet location markers to the Folium map - * As above, the bounding box tweets will need to be randomly located within the bounding box. - * Add an open button or file menu item. This will open a [`QtGui.QFileDialog`](http://zetcode.com/gui/pyqt4/dialogs/). Using this dialog, the user can supply a file of tweets and those tweets are drawn on the map. Ideally, your window loads a blank map centered on a default location. When the user loads a file of tweets, the markers are drawn and the window recenters to the mean center of the points. This will require reloading the HTML in the `QWebView`. If you struggle with this, you can simply not draw the map until the tweets are opened, and hard code the centering to Phoenix. - - Hint: The folium map object has a `__repr__` magic method that returns the map as raw HTML. The `QWebView` has a method [`setHtml()`](http://pythoncentral.io/pyside-pyqt-tutorial-qwebview/), as well as a method [`reload()`](http://pyqt.sourceforge.net/Docs/PyQt4/qwebview.html#reload). I was not able to get `reload()` to properly redraw and instead had to make a second call to `setHtml()`. -1. Include a screen shot (png, jpg) of your GUI in the PR. Please keep these small (resize to 700px width would be ideal). Git does not like large, binary files. +# Week 13 Deliverables (E9) - Due 4/19/16 +For this week make sure that you have completed the following: +* Fork Assignment 10 to your own github repository. + * You can access assignment 10 [HERE](https://github.com/Geospatial-Python/assignment_10) +* Clone the repository locally +* Note that TravisCI is still turned off for this weel + +## Deliverable +1. In the `io_geojson` module write a function that ingests the twitter data and returns a dictionary. Note that you could write this from scratch or, if a suitable library exists (maybe a built-in), utilize someone else's library. +1. Create a new Tweet class or extend the existing Point class to store: + * The tweet text + * The tweet spatial information, e.g. lat/lon coordinats (be careful with how twitter ships the data (lat/lon vs. lon/lat) + * A few (3-5) other interesting tweet attributes + + Note: Here I leave it entirely to you to decide whether the Point class should be extended to include tweet information, a Tweet class should be created that inherets from the Point class, or a Tweet class should be created that contains (composition) a Point object. + * As a comment to your PR, please let me know how you implemented the Point - Tweet relationship and why. A sentene or two is plenty. +1. Ensure that the GUI that you created last week is taking the form of a class. This will ensure that you can track state more easily. See above or [here](http://zetcode.com/gui/pyqt4/firstprograms/) for an example of what I mean by, 'the form of a class' (under the heading 'An Application Icon', the `class Example()` code block). +1. Once your current GUI window is a class extend it to: + * Have a QWebView act as a the main, central widget. + * Embed a Folium map into the QWebView + * Add the tweet location markers to the Folium map + * As above, the bounding box tweets will need to be randomly located within the bounding box. + * Add an open button or file menu item. This will open a [`QtGui.QFileDialog`](http://zetcode.com/gui/pyqt4/dialogs/). Using this dialog, the user can supply a file of tweets and those tweets are drawn on the map. Ideally, your window loads a blank map centered on a default location. When the user loads a file of tweets, the markers are drawn and the window recenters to the mean center of the points. This will require reloading the HTML in the `QWebView`. If you struggle with this, you can simply not draw the map until the tweets are opened, and hard code the centering to Phoenix. + + Hint: The folium map object has a `__repr__` magic method that returns the map as raw HTML. The `QWebView` has a method [`setHtml()`](http://pythoncentral.io/pyside-pyqt-tutorial-qwebview/), as well as a method [`reload()`](http://pyqt.sourceforge.net/Docs/PyQt4/qwebview.html#reload). I was not able to get `reload()` to properly redraw and instead had to make a second call to `setHtml()`. +1. Include a screen shot (png, jpg) of your GUI in the PR. Please keep these small (resize to 700px width would be ideal). Git does not like large, binary files. diff --git a/analytics.py b/analytics.py new file mode 100644 index 0000000..d8187aa --- /dev/null +++ b/analytics.py @@ -0,0 +1,274 @@ +#analytics +import math +import json +import sys +import os + +sys.path.insert(0, os.path.abspath('..')) + +import utils +import point + +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 + """ + temp = gj['features'] + city = "" + max_population = 0 + + for i in temp: + if (i['properties']['pop_max'] > max_population): + max_population = i['properties']['pop_max'] + city = i['properties']['name'] + + 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! + """ + #Finds how many megacities there are in the geoJSON + temp = gj['features'] + megacities = 0 + + for i in temp: + if(i['properties']['megacity'] == 1): + megacities += 1 + + + return megacities + +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 + + for point in points: + x += point[0] + y += point[1] + + x = x / len(points) + y = y / len(points) + + return x, y + +def average_nearest_neighbor_distance(points, mark=None): + """ + 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. + """ + + temp_points = [] + + if mark is not None: + for point in points: + if point.mark is mark: + temp_points.append(point) + else: + temp_points = points + + nearest = [] + + for i, point in enumerate(temp_points): + nearest.append(None) + for j, point2 in enumerate(temp_points): + if i is not j: + dist = euclidean_distance((point.x, point.y), (point2.x, point2.y)) + if nearest[i] == None: + nearest[i] = dist + elif nearest[i] > dist: + nearest[i] = dist + + mean_d = sum(nearest) / len(points) + + 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] + """ + + first = True + mbr = [0,0,0,0] + + for point in points: + if first: + first = False + mbr[0] = point[0] + mbr[1] = point[1] + mbr[2] = point[0] + mbr[3] = point[1] + + if point[0] < mbr[0]: + mbr[0] = point[0] + if point[1] < mbr[1]: + mbr[1] = point[1] + if point[0] > mbr[2]: + mbr[2] = point[0] + if point[1] > mbr[3]: + mbr[3] = point[1] + + return mbr + +def mbr_area(mbr): + """ + Compute the area of a minimum bounding rectangle + """ + area = (mbr[1] - mbr[3]) * (mbr[0] - mbr[2]) + 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 * (area / n) ** 0.5 + 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 permutations(p=99, n=100, marks=None): + perms = [] + + if marks is None: + for i in range(p): + perms.append(average_nearest_neighbor_distance(utils.create_random_marked_points(n, marks=None))) + + else: + for i in range(p): + perms.append(average_nearest_neighbor_distance(utils.create_random_marked_points(n, marks))) + + return perms + +def find_criticals(perms): + lower = min(perms) + upper = max(perms) + return lower, upper + +def check_significance(lower, upper, observed): + if observed > upper: + return True + elif observed < lower: + return True + else: + return False diff --git a/io_geojson.py b/io_geojson.py new file mode 100644 index 0000000..819c9cb --- /dev/null +++ b/io_geojson.py @@ -0,0 +1,27 @@ +#io_geojson +import json + +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 + +def read_tweets(data): + with open(data, 'r') as data: + read = data.read() + return json.loads(read) diff --git a/map.html b/map.html new file mode 100644 index 0000000..855d965 --- /dev/null +++ b/map.html @@ -0,0 +1,12168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/point.py b/point.py new file mode 100644 index 0000000..0c30250 --- /dev/null +++ b/point.py @@ -0,0 +1,36 @@ +#Point class +import sys +import os + +sys.path.insert(0, os.path.abspath('..')) + +import utils + + +class Point(object): + + def __init__(self, x, y, mark=None): + self.x = x + self.y = y + self.mark = mark + + #Magic methods + def __str__(self): + return ("{0}, {1}").format(self.x, self.y) + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __add__(self, other): + return Point(self.x + other.x, self.y + other.y) + + def __ne__(self, other): + return self.x != other.x or self.y != other.y + + #Class methods + def check_coincident(self, test): + return utils.check_coincident((self.x, self.y), test) + + def shift_point(self, x_shift, y_shift): + point = (self.x, self.y) + self.x, self.y = utils.shift_point(point, x_shift, y_shift) diff --git a/pointpattern.py b/pointpattern.py new file mode 100644 index 0000000..5001ea7 --- /dev/null +++ b/pointpattern.py @@ -0,0 +1,124 @@ +from point import Point +import analytics +import random +import numpy as np +import scipy.spatial as ss + +class PointPattern(object): + def __init__(self): + self.points = [] + + def add_point(self, point): + self.points.append(point) + + def average_nearest_neighbor_distance(self, mark=None): + return analytics.average_nearest_neighbor_distance(self.points, mark) + + def average_nearest_neighbor_distance_kdtree(self, mark_name=None): + temp_points = [] + real_points = [] + distances = [] + + if mark_name is None: + temp_points = self.points + else: + for point in self.points: + if point.mark is mark: + temp_points.append(point) + + for point in temp_points: + real_points.append((point.x, point.y)) + + kdtree = ss.KDTree(real_points) + + for p in real_points: + nearest_neighbor_distance, nearest_neighbor = kdtree.query(p, k=2) + distances.append(nearest_neighbor_distance) + + return np.mean(distances) + + def remove_point(self, index): + del(self.points[index]) + + def count_coincident_points(self): + count = 0 + coincident_list = [] + + for i, point in enumerate(self.points): + for j, point2 in enumerate(self.points): + if i is j: + continue + if j in coincident_list: + continue + #Should use the magic method in point class + if point == point2: + count += 1 + coincident_list.append(j) + return count + + def list_marks(self): + marks = [] + + for point in self.points: + if point.mark is not None and point.mark not in marks: + marks.append(point.mark) + + return marks + + def return_subset(self, mark): + #creates a list of points that have the same mark as passed + return [i for i in self.points if i.mark is mark] + + def create_random_points(self, n=None): + rand_points = [] + rand = random.Random() + marks = ['North', 'East', 'South', 'West'] + + if n is None: + n = len(self.points) + + for i in range(n): + rand_points.append(Point(rand.randint(1,100), rand.randint(1,100), mark=rand.choice(marks))) + + return rand_points + + def generate_random_points(self, min=0, max=1, count=2): + marks = ['North', 'East', 'South', 'West'] + rand_points = np.random.uniform(min, max, (count,2)) + generated_points = [] + + for i, rpoint in enumerate(rand_points): + generated_points.append(point.Point(rpoint[0], rpoint[1], mark=random.choice(marks))) + + return generated_points + + def create_realizations(self, k): + return analytics.permutations(k) + + def critical_points(self): + return analytics.find_criticals(self.create_realizations(99)) + + def compute_g(self, nsteps): + ds = np.linspace(0, 100, nsteps) + g_sum = 0 + + for step in range(nsteps): + o_i = ds[step] + min_dis = None + for i, j in enumerate(ds): + + temp = abs(j - o_i) + + if i is step: + continue + if min_dis is None: + min_dis = temp + elif min_dis > temp: + min_dis = temp + else: + continue + g_sum += min_dis + return g_sum / nsteps + + + diff --git a/small.png b/small.png new file mode 100644 index 0000000000000000000000000000000000000000..2260c635104b67abb06dd5b4e1477f0f7c14bc01 GIT binary patch literal 2099 zcmaKt`#;kQ1INGH*vuuDl)2?H*ToEHMIkhdn7ary=9b)rSa~*TnTA3{5}8WEaY=JY zTXf-Ighynm0VUNeT?US~ja1rQ! zC-3Qo?E@Zz_lXApv4j5&2q-Q=?4PP6yqgmMq-X*FB^>~^_x8C600|fXSRw+ziF*Jb z7oB_Itt|k+TI_LF9#_Wyen7tMMN)cy>RYp~Vq37iE-zn@t8Qp>2Pg02ik4@*%TW7| zD~YkoQ3=E6!Q~4L`4$;;BV2|}{bEC9LGd`vK`pp#EIj8_Dwo&Mw((Et_fqpOreAhD zj9*{8)I8S6-EQa3C6V2-`DJccuhIil2aby_0wsL9lK50s{BByg8^%MF_CM$TLW#|_ z{gkZoaImWhegUBY6%_D{nrhPolzZ_|HlJnW2}uxM##~7H?SjE^RTFlN{IqXShjt96 z{T^C#3M-`pYXwMD(HUW))Cz1x^>>LYhqpjm^4>5U74?HjWtYGG7Gk6Mqr zMO{ctbJna3p)ZUKkby*?np#KY_Whc586s%5Zub(DDQA7D;IhM`fCu=sLXu^4d_-0O z_`JgjFp}~nLt=0cU6|uoEj$9|0?71V7~9~S*b<+LY6^^EAx(Lt2h%BT5SL*dqN-b7e-72M4p$Tts~)v@D#`6$I}dDGmRl66-+h4GS*& z1wId^-4K7TdE2|M+h7d$V zGNtveV0Z%~AZ@L&@5yR0qn+%pmSE3xo>XRH2x;MZ(9zyS{d)AOTs)$^lYMoj;TXVg zl`6;ce%M1R5L;7EvV4o2x%ra2VIV~IYJ!H0cyG$N#X-vg2tWR6X>5Vzp8&5hhV%Zg zcrPukJ_pi@Kzv>G>Cp#wf=Zo@5Q~VOcnis;t20;SxR?neoq^Z_kUbO`kGk-U&pu*w zeax6a%zai$u*k8Qt;_7==2WD5LE!aGXZGx>sTJy1xIb9x7H zv$<$z>Bol@3twK6BQ(nLS+}P?*|re!4X8t!Hky(xA`M*4#v>j@S*Q8gz;Ch*`&ozH z^}SZG_kFs-(=3f%1O#g3-|O+0>t)00@*ukW7nAg%Pqny|*e1aN6GWjrNn-`EY&~!9 zS!3E9WlR}Tm7cTK;0BlTO$IAcQ6SdjZeZ)3wJ$*frs$f26e$;{P==?lBQDN1i9Fpm ziX{mkx7G%ibt}ujtUTHszPIw(HY6PTbFFjQG66ps-7$83`B>_$yX>SPZOl*3EZMJR5Z%a#*od1PHRAkj z6jRC00ItB$+1OU1<;!SQ9tytUgI2C1c13<4D|wvz{1>w^-7E_y&#-`}J?bg>;DR~# zIa7#gsBGT__j8>ft=Tm6w7pfz48|XcAYA*9*Ytjr(&T+kAs(}=-8H}F+Hp-)MVC=Z z@#vFN<5W(~b9MeQXUci^51jnOBrZC=x!AezB+^E`cT3pT4ZX-qSb1JqO58&!p}&6EL6{f8kF&K%CTU`Ot-DTnKOOTPLwen zi01eol+OS98$oYY#8y-n*S~vX4>yjSx*>34`G>a_%>~k^`q|}cPWT~NMb63~2P<)< zsVekz@vR!GH0xpf@X!&B?#GZ^x@Trnq8X&y3q`L#8{ZO3j1&cnD=PWr_0l{pnHRsb zVb@zphq*&PhZ!Svg!W#Jfg(QE2t#J{jQvsK>&M{}h{>JP_8(E{}FvUl0jd`WRT)U#O;oCHR@HyGJNWMV;k zwe6z3R9Fc3$>;)x9>{T3i&5P0BYYY00&fETksC~#7MU957|oRcp%T*YheQ6z`j_<& z640@yhE%%O5ioJ}-3ceyBJUMqOQhSXik|z;JSxlG4KMQ%!Q^hSDH9)F3?)_R9^W{4 z#8(}Kh^(u{zvim3O|?e7GBp75#rb9xcycrr)bWCi5=5V-Rr zR<%JoM)esRAtR>OJ>tG%&#=)NnnbbnSB9I?Bw;8GCEqis_W!lG@5+5i2AA(af!xoe U#84*d&wb$o_BI4utu-<2U(B?uY5)KL literal 0 HcmV?d00001 diff --git a/tmp/map.html b/tmp/map.html new file mode 100644 index 0000000..21cbcb3 --- /dev/null +++ b/tmp/map.html @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + \ No newline at end of file diff --git a/tweet.png b/tweet.png new file mode 100644 index 0000000000000000000000000000000000000000..1328a612f0c529f5cf4966edacbdf9c1303fd599 GIT binary patch literal 2229 zcmbVOX;2es8jgw?{;0wL*yY)m>PK|&N41RX~? zN5m+Ka_Hzd9wRWw03zz5c%UGRl*%D2;5C3Uh>GiMN5$Q(vgXHjRrhzj&-1+3SJmGJ z1^QWAEVRI2FxG-qybyFGm|k-%`hA2k8qr~a&No6Aib!?IA`Oh;NRR{=5GX}5I0P0+ zQZ_cjo*2vwsXQz~7aGyS*bL|^}$-J3xWUR z#uu%%VJT{u90F^RB#juYhtzorjOOmog-nL1H>@=pIa(Ca1|A|#Qo<^ofXBw8CnSkn z!s0U+dRt{!a`IIokwB1ak*R$1o8MxnmdQf zfVfm24oG2Ae5bGil~yNGiQy?-IjZ{!OaD_Wi>rY}Iz$tOARDGSASe;hA=*Sl4RAy0 zfKVist4wQCc|JzVgEjI^u!OHcl)#7lvgBXT=X3uzZg*cQgGuGlX}&xzk3;3-KVc>R zPtM4wGh|b9{8zI~ZJ`}#ntpD5bn*G}z$)~{Xwa*1BYvn4gE1Qr@Hk=m`!^$^17gB$ z*H5$@n%`?hK5&T{Md_Z#~S zBfYjsBli*~78|O6IsLLlBb!D04r||~58Qpr>QJEKAg<^>sjVvG)ptHTd}o;0D$BRj zOUhsH=wwkR&w3J@Vr8B`I=HQ-hB$p!X7#)yqrZ;bc{@G9ty5d6Zf@)_B&PZ_#ccV- zVE^GaGT$pb#}}harMq?dgd_J>vP8bt_CCG zWCG@j{<#@-W#F8ve?$HuBb4sj;W7S>hQgTUQ$u?9I)OtO}09$UMGzaW|9f z9F*WHaS_gPNgQ$Ho+kA1>K6|={&;D3^@HI2@3U(eIE%h3!+5)E*Vh)DysXHc{ZL#6 zuJFH9lkl_I&ibF)^c`bY()*R`apR=pd#VZ|)u&UI#`Z+-TDWJLXvvTFNqZcU9|)V* z35!$UIA#EiUs_W*7%<>8n7O09;=(dV#<2m|=AnYoe@MDChov;fa`iWBh{|QZ(|#@U za5djvP~hOdAI>bQE00G`&>xLlovF{^;ttk5Q{a33q`qg*;=qg_~i#t!?l!dRUZqr!iwC}rkcJ|~^ z$batO&~qP5LoIu5%FO`oJexYw#G;%n?dg}RHdVS?1{WT#SOKz!BNx3L^?Up~t2>W# z!`7Tyyh>_Pi}&@v_nzt1J&Xe!PIa$79BaR$_4qf9M>1^3-9~7Cl|(-6TM^V*S&6r1 z6GGRYJ9UXurnPimlSVj{vvbi5o4C$>Dc643w+fRV=DdY4?bb+KBbgf-nI4?jNZ!)A z-CL6HBHzo}B+{uIZqp0$NB8$hiYJM7Ghe@puo+(QlXT|eqpQ1Kchk!(h?@zgz$Qsi z#cww|8q|Zmq&mY9Z0ep^t6)Rner-^6-d7czBD=hqE1JkQM$3BV*8aVDn`-LxziPct z%?uTW>(Bp;J7!fs=JMiMjGtH3AB%!*(uKBHGR*>w-a1WoLE-$X@;Mn{K2BBoUF|(< z-Z6tBcd{Q4@8nsv2e&RRQ3qb%Y88;u`s6^y$_K#hU0S@=(t#_^!zG{{=zup_$iuF^_-ujOa8rmk; bq)o%%;tS(;f$A31kA%QCkayZAe%rqRhiQk3 literal 0 HcmV?d00001 diff --git a/tweet.py b/tweet.py new file mode 100644 index 0000000..6641ae7 --- /dev/null +++ b/tweet.py @@ -0,0 +1,13 @@ +import utils +from point import Point + +class Tweet(object): + def __init__(self, tweet_dic): + self.tweet = tweet_dic['text'] + self.lat = tweet_dic['place']['bounding_box']['coordinates'][0][1] + self.lng = tweet_dic['place']['bounding_box']['coordinates'][0][0] + self.user = tweet_dic['user']['screen_name'] + self.source = tweet_dic['source'] + self.followers = tweet_dic['user']['followers_count'] + self.point = Point(self.lat, self.lng) + diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..6dd3d1d --- /dev/null +++ b/utils.py @@ -0,0 +1,129 @@ +#utils +import random +import point + +def create_random_marked_points(n, marks=[]): + rand = random.Random() + rand_points = [] + + if marks is None: + for i in range(n): + rand_points.append(point.Point(rand.randint(0, 100), rand.randint(0,100))) + else: + for i in range(n): + rand_points.append(point.Point(rand.randint(0, 100), rand.randint(0,100), rand.choice(marks))) + + return rand_points + +def create_random_points(n): + rand = random.Random() + random_points = [(rand.randint(0,100), rand.randint(0,100)) for i in range(n)] + return random_points + +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] \ No newline at end of file diff --git a/view.py b/view.py new file mode 100644 index 0000000..18c95d4 --- /dev/null +++ b/view.py @@ -0,0 +1,50 @@ +import sys +from PyQt4 import QtGui + +class Example(QtGui.QMainWindow): + + def __init__(self): + super(Example, self).__init__() + + self.initUI() + + def initUI(self): + + textEdit = QtGui.QTextEdit() + self.setCentralWidget(textEdit) + + exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self) + exitAction.setShortcut('Ctrl+Q') + exitAction.setStatusTip('Exit application') + exitAction.triggered.connect(self.close) + + self.statusBar() + + menubar = self.menuBar() + fileMenu = menubar.addMenu('&File') + fileMenu.addAction(exitAction) + + toolbar = self.addToolBar('Exit') + toolbar.addAction(exitAction) + + self.setGeometry(300, 300, 250, 150) + self.setWindowTitle('Statusbar') + + self.center() + self.show() + + def center(self): + + qr = self.frameGeometry() + cp = QtGui.QDesktopWidget().availableGeometry().center() + qr.moveCenter(cp) + self.move(qr.topLeft()) + +def main(): + + app = QtGui.QApplication(sys.argv) + ex = Example() + sys.exit(app.exec_()) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/view2.py b/view2.py new file mode 100644 index 0000000..1e5f894 --- /dev/null +++ b/view2.py @@ -0,0 +1,61 @@ +import os +import sys +from PyQt4 import QtGui, QtWebKit, QtCore +import folium +import tweet +import io_geojson + +class View(QtGui.QMainWindow): + + def __init__(self): + super(View, self).__init__() + self.init_ui() + + def init_ui(self): + # self.setGeometry(300, 300, 400, 325) + self.setWindowTitle('Tweets on a Map!') + self.map_loc = 'map.html' + self.setWindowIcon(QtGui.QIcon('small.png')) + + self.web_view = QtWebKit.QWebView() + self.map = folium.Map(location=[33.4255, -111.9400], zoom_start=12) + self.map.save(self.map_loc) + self.web_view.load(QtCore.QUrl(self.map_loc)) + self.setCentralWidget(self.web_view) + os.makedirs('tmp', exist_ok=True) + + load_action = QtGui.QAction(QtGui.QIcon('tweet.png'), 'Exit', self) + load_action.setShortcut('Ctl+O') + load_action.triggered.connect(self.open) + + toolbar = self.addToolBar('Open') + toolbar.addAction(load_action) + + self.show() + + def open(self): + file_name = QtGui.QFileDialog.getOpenFileName(parent=self, caption='Open Twitter Data', filter='*.json') + self.tweets_loc = [] + tweet_dic = io_geojson.read_tweets(file_name) + tweets = [] + for twit in tweet_dic: + tweets.append(tweet.Tweet(twit)) + + #print(tweets[1].user) + for twet in tweets: + lat = twet.lat[1] + lng = twet.lng[0] + + folium.Marker([lat, lng], popup=twet.user).add_to(self.map) + + self.map.save(self.map_loc) + self.web_view.load(QtCore.QUrl(self.map_loc)) + print(len(tweets)) + +def main(): + app = QtGui.QApplication(sys.argv) + view = View() + sys.exit(app.exec_()) + +if __name__ == '__main__': + main()