The main reverse geocoder class
| 91 | |
| 92 | @singleton |
| 93 | class RGeocoder(object): |
| 94 | """ |
| 95 | The main reverse geocoder class |
| 96 | """ |
| 97 | def __init__(self, mode=2, verbose=True, stream=None): |
| 98 | """ Class Instantiation |
| 99 | Args: |
| 100 | mode (int): Library supports the following two modes: |
| 101 | - 1 = Single-threaded K-D Tree |
| 102 | - 2 = Multi-threaded K-D Tree (Default) |
| 103 | verbose (bool): For verbose output, set to True |
| 104 | stream (io.StringIO): An in-memory stream of a custom data source |
| 105 | """ |
| 106 | self.mode = mode |
| 107 | self.verbose = verbose |
| 108 | if stream: |
| 109 | coordinates, self.locations = self.load(stream) |
| 110 | else: |
| 111 | coordinates, self.locations = self.extract(rel_path(RG_FILE)) |
| 112 | |
| 113 | if mode == 1: # Single-process |
| 114 | self.tree = KDTree(coordinates) |
| 115 | else: # Multi-process |
| 116 | self.tree = KDTree_MP.cKDTree_MP(coordinates) |
| 117 | |
| 118 | def query(self, coordinates): |
| 119 | """ |
| 120 | Function to query the K-D tree to find the nearest city |
| 121 | Args: |
| 122 | coordinates (list): List of tuple coordinates, i.e. [(latitude, longitude)] |
| 123 | """ |
| 124 | if self.mode == 1: |
| 125 | _, indices = self.tree.query(coordinates, k=1) |
| 126 | else: |
| 127 | _, indices = self.tree.pquery(coordinates, k=1) |
| 128 | return [self.locations[index] for index in indices] |
| 129 | |
| 130 | def load(self, stream): |
| 131 | """ |
| 132 | Function that loads a custom data source |
| 133 | Args: |
| 134 | stream (io.StringIO): An in-memory stream of a custom data source. |
| 135 | The format of the stream must be a comma-separated file |
| 136 | with header containing the columns defined in RG_COLUMNS. |
| 137 | """ |
| 138 | stream_reader = csv.DictReader(stream, delimiter=',') |
| 139 | header = stream_reader.fieldnames |
| 140 | |
| 141 | if header != RG_COLUMNS: |
| 142 | raise csv.Error('Input must be a comma-separated file with header containing ' + \ |
| 143 | 'the following columns - %s. For more help, visit: ' % (','.join(RG_COLUMNS)) + \ |
| 144 | 'https://github.com/thampiman/reverse-geocoder') |
| 145 | |
| 146 | # Load all the coordinates and locations |
| 147 | geo_coords, locations = [], [] |
| 148 | for row in stream_reader: |
| 149 | geo_coords.append((row['lat'], row['lon'])) |
| 150 | locations.append(row) |