# StoreLocator
A command-line tool to find the nearest store to a given address or zip code from a CSV of stores.
## Getting Started
To get started clone this repo, and if you don't want to install all the dependencies globally (and you shouldn't want to), make sure you have something like Virtualenv installed on your machine.
### Prerequisites
To avoid potential conflicts, create a virtual environment and activate it before following installation instructions.
```
virtualenv -p python3 env
. env/bin/activate
```
### Installing
Follow these steps to setup StoreLocator.
```
pip install storelocator
```
### Optional Setup
Populate config variables in constants.py if you not planning on using the provided defaults.
```
# Config
STORES_CSV = 'store-locations.csv'
DEFAULT_OUTPUT = 'text'
DEFAULT_UNITS = 'mi'
DEFAULT_ENCODING = 'utf-8-sig'
DEFAULT_DELIMITER = ','
DISTANCE_PRECISION = 2
# CSV Field Names
STORE_FIELDS = {
'NAME': 'Store Name',
'LOCATION': 'Store Location',
'COUNTY': 'County',
'ADDRESS': 'Address',
'CITY': 'City',
'STATE': 'State',
'ZIP_CODE': 'Zip Code',
'LATITUDE': 'Latitude',
'LONGITUDE': 'Longitude',
'DISTANCE': 'Distance'
}
```
Once you are all set up, you can use StoreLocator to find the nearest store by address or zip code. Optionally, you can also choose the units for distance (mi or km) and the format you want your results outputted as (text or json).
```
Find Store
find_store will locate the nearest store (as the vrow flies) from
store-locations.csv, print the matching store address, as well as
the distance to that store.
Usage:
find_store --address="<address>"
find_store --address="<address>" [--units=(mi|km)] [--output=text|json]
find_store --zip=<zip>
find_store --zip=<zip> [--units=(mi|km)] [--output=text|json]
Options:
--zip=<zip> Find nearest store to this zip code. If there are multiple best-matches, return the first.
--address Find nearest store to this address. If there are multiple best-matches, return the first.
--units=(mi|km) Display units in miles or kilometers [default: mi]
--output=(text|json) Output in human-readable text, or in JSON (e.g. machine-readable) [default: text]
Example
find_store --address="1770 Union St, San Francisco, CA 94123"
find_store --zip=94115 --units=km
```
## Running the tests
If you have cloned this repo and installed dependencies from requirements.txt you can run tests like so:
```
nose2
```
## About StoreLocator
StoreFinder was built to be flexible and scalable enough to allow for the cli functionality to be easily extended, to work with larger datasets than the one provided, and to be included modularly for use outside of the command prompt.
There are many different approaches one can take to find the nearest point in a dataset, and certainly there are improvements that can be made to this approach.
StoreFinder handles addresses and zip codes in very much the same way. Both pass through a geocoding service (default is google but other providers can easily be used) and are converted, if possible, to a latitudinal and longitudinal coordinate.
The parsing of the csv containing store location data is handled via the StoresParser object. The StoresParser reads in the csv and creates a list of stores (dicts). At the same time, the latitudinal and longitudinal coordinates for all of the stores are spatially indexed via a KDTree implementation on the StoresParser object.
By utilizing a KDTree data structure, querying for the nearest store is optimized to an Nlog(n) time complexity, reducing the number of distance calculations needed to calculated to find the nearest store. Building this tree does come with the added cost of space for storing the tree and the time required initially to populate the tree.
To benefit from this approach it was important to make sure that the KDTree did not have to repopulate every time a new search was conducted. To achieve this, the StoresParser has a save method that saves the current instance to a .pkl file once the KDTree is populated. Then, StoresParser has a static method called get_StoresParser that returns either a saved instance of StoresParser, or if no .pkl file exists, returns a new instance after it populates its KDTree.
In order for lat/lon coordinates to be stored in a KDTree and spatially represented accurately, they have to be converted to a new type of coordinates (ECEF X, Y, Z) that can be used to calculate euclidean distances.
Finding the nearest store first queries the tree to receive the closest possible results, then from that list of results, a traditional brute-force and iterative comparison is conducted to find the closest.
Distance calculations are based of the Haversine formula.
https://en.wikipedia.org/wiki/Haversine_formula
## Authors
* Austin Brown
Raw data
{
"_id": null,
"home_page": "https://github.com/austinbrown34/hifi",
"name": "hifi",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "",
"author": "Austin Brown",
"author_email": "austinbrown34@gmail.com",
"download_url": "",
"platform": null,
"description": "# StoreLocator\n\nA command-line tool to find the nearest store to a given address or zip code from a CSV of stores.\n\n## Getting Started\n\nTo get started clone this repo, and if you don't want to install all the dependencies globally (and you shouldn't want to), make sure you have something like Virtualenv installed on your machine.\n\n### Prerequisites\n\nTo avoid potential conflicts, create a virtual environment and activate it before following installation instructions.\n\n```\nvirtualenv -p python3 env\n. env/bin/activate\n```\n\n### Installing\n\nFollow these steps to setup StoreLocator.\n\n```\npip install storelocator\n```\n\n### Optional Setup\n\nPopulate config variables in constants.py if you not planning on using the provided defaults.\n\n```\n# Config\n\nSTORES_CSV = 'store-locations.csv'\nDEFAULT_OUTPUT = 'text'\nDEFAULT_UNITS = 'mi'\nDEFAULT_ENCODING = 'utf-8-sig'\nDEFAULT_DELIMITER = ','\nDISTANCE_PRECISION = 2\n\n# CSV Field Names\nSTORE_FIELDS = {\n 'NAME': 'Store Name',\n 'LOCATION': 'Store Location',\n 'COUNTY': 'County',\n 'ADDRESS': 'Address',\n 'CITY': 'City',\n 'STATE': 'State',\n 'ZIP_CODE': 'Zip Code',\n 'LATITUDE': 'Latitude',\n 'LONGITUDE': 'Longitude',\n 'DISTANCE': 'Distance'\n}\n```\n\nOnce you are all set up, you can use StoreLocator to find the nearest store by address or zip code. Optionally, you can also choose the units for distance (mi or km) and the format you want your results outputted as (text or json).\n\n```\nFind Store\n find_store will locate the nearest store (as the vrow flies) from\n store-locations.csv, print the matching store address, as well as\n the distance to that store.\n\nUsage:\n find_store --address=\"<address>\"\n find_store --address=\"<address>\" [--units=(mi|km)] [--output=text|json]\n find_store --zip=<zip>\n find_store --zip=<zip> [--units=(mi|km)] [--output=text|json]\n\nOptions:\n --zip=<zip> Find nearest store to this zip code. If there are multiple best-matches, return the first.\n --address Find nearest store to this address. If there are multiple best-matches, return the first.\n --units=(mi|km) Display units in miles or kilometers [default: mi]\n --output=(text|json) Output in human-readable text, or in JSON (e.g. machine-readable) [default: text]\n\nExample\n find_store --address=\"1770 Union St, San Francisco, CA 94123\"\n find_store --zip=94115 --units=km\n```\n\n## Running the tests\n\nIf you have cloned this repo and installed dependencies from requirements.txt you can run tests like so:\n\n```\nnose2\n```\n\n## About StoreLocator\n\nStoreFinder was built to be flexible and scalable enough to allow for the cli functionality to be easily extended, to work with larger datasets than the one provided, and to be included modularly for use outside of the command prompt.\n\nThere are many different approaches one can take to find the nearest point in a dataset, and certainly there are improvements that can be made to this approach.\n\nStoreFinder handles addresses and zip codes in very much the same way. Both pass through a geocoding service (default is google but other providers can easily be used) and are converted, if possible, to a latitudinal and longitudinal coordinate.\n\nThe parsing of the csv containing store location data is handled via the StoresParser object. The StoresParser reads in the csv and creates a list of stores (dicts). At the same time, the latitudinal and longitudinal coordinates for all of the stores are spatially indexed via a KDTree implementation on the StoresParser object.\n\nBy utilizing a KDTree data structure, querying for the nearest store is optimized to an Nlog(n) time complexity, reducing the number of distance calculations needed to calculated to find the nearest store. Building this tree does come with the added cost of space for storing the tree and the time required initially to populate the tree.\n\nTo benefit from this approach it was important to make sure that the KDTree did not have to repopulate every time a new search was conducted. To achieve this, the StoresParser has a save method that saves the current instance to a .pkl file once the KDTree is populated. Then, StoresParser has a static method called get_StoresParser that returns either a saved instance of StoresParser, or if no .pkl file exists, returns a new instance after it populates its KDTree.\n\nIn order for lat/lon coordinates to be stored in a KDTree and spatially represented accurately, they have to be converted to a new type of coordinates (ECEF X, Y, Z) that can be used to calculate euclidean distances.\n\nFinding the nearest store first queries the tree to receive the closest possible results, then from that list of results, a traditional brute-force and iterative comparison is conducted to find the closest.\n\nDistance calculations are based of the Haversine formula.\n\nhttps://en.wikipedia.org/wiki/Haversine_formula\n\n## Authors\n\n* Austin Brown\n",
"bugtrack_url": null,
"license": "",
"summary": "Command-line tool to find nearest store.",
"version": "6.0.0",
"project_urls": {
"Homepage": "https://github.com/austinbrown34/hifi"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "582aa8dc4d31a141078c5cab49b83cb683253db1820553c3338c380c19c1da19",
"md5": "20080d3a39d00636210ea099de57ab94",
"sha256": "4ddd16207d0245b9aa15f076d277aa52d3fb0da60d073828be4ee1142f8c05ca"
},
"downloads": -1,
"filename": "hifi-6.0.0-py3.9.egg",
"has_sig": false,
"md5_digest": "20080d3a39d00636210ea099de57ab94",
"packagetype": "bdist_egg",
"python_version": "6.0.0",
"requires_python": null,
"size": 210760,
"upload_time": "2023-05-15T23:03:31",
"upload_time_iso_8601": "2023-05-15T23:03:31.924054Z",
"url": "https://files.pythonhosted.org/packages/58/2a/a8dc4d31a141078c5cab49b83cb683253db1820553c3338c380c19c1da19/hifi-6.0.0-py3.9.egg",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-05-15 23:03:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "austinbrown34",
"github_project": "hifi",
"github_not_found": true,
"lcname": "hifi"
}