PK!8Veepoi_kml/__init__.py__version__ = '0.1.0' from .poi import * from .fake_poi_list_generator import make_fake_poi_csv PK!I(vU"poi_kml/fake_poi_list_generator.pyfrom faker import Faker import usaddress import phonenumbers as pn import pandas as pd import random from pathlib import Path OUTPUT_DIR = 'output' def new_record(): fake = Faker('en_US') company = fake.company() address = fake.address().replace('\n',', ') g = usaddress.tag(address)[0] city = g.get('PlaceName') state = g.get('StateName') zip = g.get('ZipCode') phone = fake.phone_number() phone = pn.format_number(pn.parse(phone, 'US'), pn.PhoneNumberFormat.NATIONAL) lat,lng = fake.latlng() review_count = random.randint(1,300) return (company, address, city, state, zip, phone, float(lat), float(lng), review_count) def make_fake_poi_csv(filename, n): records = [] for i in range(n): records.append(new_record()) header = ['Name', 'Address', 'City', 'State', 'Zip', 'Phone', 'Latitude', 'Longitude', 'Review Count',] df = pd.DataFrame.from_records(records, columns=header) # print(df) output_dir = Path('.', 'output') output_dir.mkdir(parents=True, exist_ok=True) df.to_csv(output_dir/filename, index=False) return Path(output_dir/filename) # SAMPLE_FILENAME = 'sample_poi.csv' # make_poi_csv(SAMPLE_FILENAME, n=50) PK! HHpoi_kml/poi.py#-----------------------------------------------------------------------------# # Manny Ochoa -- 17 November 2018 -- Ver. 1.0.0 -- initial revision #-----------------------------------------------------------------------------# ''' Point of Interest list to KML (poi.py) This module defines classes and functions for converting a CSV file of points of interest with addresses to a KML file for importing into mapping software. To test it, use fake_poi_list_generator.py to generate a sample dataset. ''' #-----------------------------------------------------------------------------# # LIBRARIES #-----------------------------------------------------------------------------# from pathlib import Path import pandas as pd import simplekml import uszipcode import geocoder #----------------------------------------------------------------------------# # CLASSES AND FUNCTIONS #----------------------------------------------------------------------------# class POIdb(object): ''' Filters a list of points of interest based on distance from a street address (using an OpenStreetMaps API) and/or by state. Creates a kml file for uploading to Google maps. Expects a csv database with at least the following columns (in any order): Name,Address,State,Zip,Phone,Latitude,Longitude ''' # CLASS CONSTANTS ERR_MSG_NO_ADDRESS = 'Please set reference address with set_home().' DEFAULT_KML_FILENAME = 'poi_list' def __init__(self, filename, home=None): self.file = Path(filename) self.home = home self.df_orig = pd.read_csv(self.file) self.validate_df(self.df_orig) self.df = self.df_orig.copy() def __len__(self): return len(self.df) def __str__(self): print(self.df) return '' def validate_df(self, df): header = 'Name,Address,State,Zip,Phone,Latitude,Longitude'.split(',') if not all(k in df for k in header): raise MissingDataColumns(MissingDataColumns.msg) def fill_states_and_zip(self, df): '''Updates Zip and State if not in df, given FullAddress. Might take a while, due to multiple calls to OpenStreetMaps.''' records = [] for id,row in df.iterrows(): g = geocoder.osm(row['FullAddress']) records.append((g.state, g.postal)) df['Zip'] = [Zip for (Zip,State) in records] df['State'] = [Zip for (Zip,State) in records] return self def _update_home_coords(self): g = geocoder.osm(self.home) self.lat, self.lng = g.latlng self.zip = g.postal self.state = g.state return self def set_home(self, address): self.home = address self._update_home_coords() return self def reload(self): self.df = self.df_orig.copy() return self def sort(self, **kwargs): '''Sorts the data (Pandas df) in place''' self.df.sort_values(**kwargs, inplace=True) return self def filter(self, states=None, miles=None, reload=True): if reload: self.reload() # start with complete initial dataset before filtering if states: state_set = states.upper().split() self.df = self.df[self.df.State.isin(state_set)] if miles: if self.home is None: # check for address raise AssertionError(self.ERR_MSG_NO_ADDRESS) self._update_home_coords() # update coordinates zip_data = uszipcode.SearchEngine().by_coordinates( lat=self.lat, lng=self.lng, radius=miles, returns=None) valid_zip_codes = set([record.zipcode for record in zip_data] + [self.zip]) # always include home zip code self.df = self.df[self.df.Zip.isin(valid_zip_codes)] return self def to_kml(self,filename=None): kml=simplekml.Kml() for id,row in self.df.iterrows(): kml.newpoint( name=row['Name'], description=str(row['Address']) + '\n' + str(row['Phone']), coords=[(float(row['Longitude']), float(row['Latitude']))]) output_filename = filename if filename else self.DEFAULT_KML_FILENAME output_dir = Path('.', 'output') output_dir.mkdir(parents=True, exist_ok=True) kml.save(output_dir/(output_filename + '.kml')) print('Created file ' + str(Path(output_filename + '.kml'))) return self class MissingDataColumns(Exception): '''Raised when the data is missing columns from the expected ones.''' msg = 'Please use a csv database with at least the following columns\n\ (in any order): Name,Address,State,Zip,Phone,Latitude,Longitude' pass #----------------------------------------------------------------------------# # SAMPLE SCRIPT #----------------------------------------------------------------------------# ''' First generate a test csv file ''' # import fake_poi_list_generator as fakepoi # fake_file = fakepoi.make_fake_poi_csv('sample_poi.csv', n=20) ''' Example for generating a kml file ''' # db = POIdb(fake_file) # db.set_home('1200 E California Blvd, Pasadena, CA 91125') # db.filter(miles=25) # db.to_kml(filename='poi_near') # print(db.sort(by='Name')) PK!KUBBpoi_kml-0.1.0.dist-info/LICENSEMIT License Copyright (c) 2018 Manuel Ochoa Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HnHTUpoi_kml-0.1.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HXda poi_kml-0.1.0.dist-info/METADATATo0xڮJnj heGj Xvhٴ}wI M'zݓoTxѻ1 1+= ndd\~c,;6K6F4w=PB1KaA ]Bn'F_G)-|PL{19I@&c6ˢf )15k+zn^u& ߊ'ox+|2#lo{Arߔ]N|ȳH'U:Qwt"M; ,ަrH+pG?F{оh815O:Zd%w)92F+6eNϱXi~Y&1dD p+XϞ߰*$Coo"Ƙ c S(L柄N2'y$ ꌊqB]B,D:l̅/LiSJ}4W&)vZ쳴X4X{)qJ?iʥKbqH&U _ RU?qUc>l;A3s(J[s^uIS,J[T$]/;x=}E.QK>۴ Zt qD o7;o!kGmERXnH)Kj7jPK!Hcpoi_kml-0.1.0.dist-info/RECORDur0{, p%EQb$JA-3ӋmXqQgG tfdUDW ^Va"4B͋odExi~)9);C^<93O93 3"6(k]!+NbgK {cvFB'"pNly֬6|Prոb#J#0F< {]Χhu, ⸇iO:Snt$r@u7vzԸFNf{e2pbG,ayde tQhZfh><=ӞJqV'3̋ۋ:Ow kSGSϷPK!8Veepoi_kml/__init__.pyPK!I(vU"poi_kml/fake_poi_list_generator.pyPK! HHpoi_kml/poi.pyPK!KUBB poi_kml-0.1.0.dist-info/LICENSEPK!HnHTUpoi_kml-0.1.0.dist-info/WHEELPK!HXda poi_kml-0.1.0.dist-info/METADATAPK!Hc!!poi_kml-0.1.0.dist-info/RECORDPK"