{ "info": { "author": "Alessandro", "author_email": "alessandro2.negrini@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# PyCristoforo\n\n**v2.0.0**\n\nThe new python library for the generation of **contestualized random** coordinates.\nPyCristoforo takes in input a country name and it generates random coordinates, inside that country (not including the sea/ocean sections).\n\n**Python version supported: 3.6, 3.7**\n\nLatest updates\n-----------------\n\n| Date | Description |\n| ------------- | ------------- |\n| 30/06/2019 | PyCristoforo 1.0.0 published on PyPi |\n| 08/07/2019 | PyCristoforo 1.0.0.post4 published on PyPi |\n| 09/07/2019 | PyCristoforo 1.1.0 published on PyPi |\n| 28/07/2019 | PyCristoforo 2.0.0 published on PyPi |\n\n\nTable of contents\n-----------------\n- [Random Point generation](#random-point-generation)\n- [Requirements](#requirements)\n- [Install](#install)\n- [Usage](#usage)\n- [Build](#build)\n- [Running tests](#running-tests)\n- [ChangeLog](#changelog)\n- [License](#license)\n- [What next](#what-next)\n- [Authors](#authors)\n- [Notes](#notes)\n\nRandom Point generation\n-----------\nIn this section you can find some details about random coordinates generation method.\n\n**Version 1**\n\nPyCristoforo v1 implements a very simple algorithm for random point generation:\n- starting from the country Polygon shape, it first gets the rectangle around it and then the min/ max latitudes and longitude.\n```\n# getting min, max lat/lng\nmin_lng = get_min_lng(shape)\nmin_lat = get_min_lat(shape)\nmax_lng = get_max_lng(shape)\nmax_lat = get_max_lat(shape)\n```\n![Germany Envelope](pycristoforo/resources/env_germ.png?raw=true \"Germany Envelope\")\n\n- inside it, the random coordinates are generated in a uniform way\n```\n# generate random float between [min_lng, max_lng)\nval1 = numpy_random.uniform(min_lng, max_lng)\n# generate random float between [min_lat, max_lat)\nval2 = numpy_random.uniform(min_lat, max_lat)\n```\n![Germany Envelope Points KO](pycristoforo/resources/env_germ_p2.png?raw=true \"Germany Envelope Points KO\")\n\n- finally, only the points inside the country shape are kept, the ones outside are discarded.\nNew points are then generated until reaching the user expected number.\n```\n# random point generation\nwhile counter != points:\n if random_point.within(shape):\n ...\n list_of_points.append(ran_point)\n counter += 1\n```\n![Germany Envelope Points OK](pycristoforo/resources/env_germ_p1.png?raw=true \"Germany Envelope Points OK\")\n\nAs said above, the algorithm is very simple, but also very inefficient.\n\nBenchmark:\n* Country: \"Germany\"\n* NumPoints: 100k\n* Time: 4min 20sec\n\n**Version 2**\n\nIn order to make the algorithm faster and more robust (https://codereview.stackexchange.com/questions/69833/generate-sample-coordinates-inside-a-polygon), v2 changes the way random points are generated:\n- country polygon is triangulated and the area of each triangle is then calculated;\n- for each sample:\n * pick the triangle \ud835\udc61 containing the sample, using random selection weighted by the area of each triangle.\n * pick a random point uniformly in the triangle, as follows:\n * pick a random point \ud835\udc65,\ud835\udc66 uniformly in the unit square.\n * If \ud835\udc65+\ud835\udc66>1, use the point 1\u2212\ud835\udc65,1\u2212\ud835\udc66 instead. The effect of this is to ensure that the point is chosen uniformly in the unit right triangle with vertices (0,0),(0,1),(1,0)\n * Apply the appropriate affine transformation to transform the unit right triangle to the triangle \ud835\udc61.\n\nThe hard constraint of this method is that it works only for **convex polygons**, and therefore some points may be generated out of the country shape (convex hull).\n![Germany Convex Hull Points KO](pycristoforo/resources/germ_hull_p3.png?raw=true \"Germany Convex Hull Points KO\")\n\nAll points are checked if lying inside the country shape.\nFor each point outside the country, a new one is generated.\n\n![Germany Convex Hull Points KO](pycristoforo/resources/germ_hull_p4.png?raw=true \"Germany Convex Hull Points KO\")\n\nThis method almost 20% more faster on benchmark.\n\nBenchmark:\n* Country: \"Germany\"\n* NumPoints: 100k\n* Time: 3min 30sec\n\nRequirements\n------------\n* numpy v1.16.4\n* Shapely v1.6.4.post2\n\nDetails [here](requirements.txt)\n\nResources\n---------\n* World countries geoJSON ([link](https://datahub.io/core/geo-countries#resource-countries))\n\nInstall\n-------\nPyCristoforo is very easy to install and use (please be sure to have installed dependencies (section 'Requirements')\n```\npip3 install pycristoforo\n```\n\nUsage\n-------\n\n* Now you can import it in your script:\n```\nimport pycristoforo as pyc\n```\n\n* You can now load the geojson of the country you'd like to generate geocoordinates in:\n```\ncountry = pyc.get_shape(\"Italy\")\n```\nThe supported input for `get_shape` method are not only the extended country names: you can either use `ISO_A3` code.\n[Here](COUNTRIES.csv) you can find the supported input (country_name, ISO_A3).\nMethod is case insensitive:\n```\ncountry = pyc.get_shape(\"ITALY\")\n```\nbehaves the same as:\n```\ncountry = pyc.get_shape(\"italy\")\n```\n\n`country` var contains now the shape of the country passed in input (usually a `shapely Poligon`or `MultiPoligon`):\n```\nMULTIPOLYGON (((12.127777 47.00166300000012, 12.13611 46.966942, 12.16027600000012 46.92805, 12.18138900000014 46.909721, 12.189722 46.90610500000014, 12.232222 46.888885, 12.301666 46.84111, 12.378611 46.72666, 12.38888700000012 46.715553, ... , 12.047777 36.753052, 12.03833200000014 36.747215, 12.027777 36.74222, 12.01583 36.738327)))\n```\n\n* Now that country shape has been loaded, it's time to get `n` random geocoordinates.\nSuppose to generate 100 geocoordinates:\n```\npoints = pyc.geoloc_generation(country, 100, \"Italy\")\n```\n\n`points` is a list of Points:\n```\n00 = {dict} {'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [13.963703154465053, 42.591335534115316]}, 'properties': {'point': 1, 'country': 'Italy'}}\n01 = {dict} {'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [11.659857182901725, 43.95787059805974]}, 'properties': {'point': 2, 'country': 'Italy'}}\n02 = {dict} {'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [7.992769814920238, 45.89632889069682]}, 'properties': {'point': 3, 'country': 'Italy'}}\n...\n99 = {dict} {'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [6.112769314920238, 45.45632889569111]}, 'properties': {'point': 100, 'country': 'Italy'}}\n```\n\nYou can now iterate through the list and make good use of them.\n\n* Print what you just generated:\n```\ngeoloc_print(points, ',')\n```\n\n* A utility method is the `get_envelope` one:\n```\nenv = pyc.get_envelope(country)\n```\n\nBuild\n------\n```\npython3 setup.py sdist bdist_wheel\n```\n\nRunning tests\n-------------\nWork in progress\n\nChangeLog\n---------\nCurrent version: 2.0.0\n\n[Changelog](CHANGELOG.rst)\n\nLicense\n-------\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details\n\nWhat Next\n------------\n* v2.1.0: random points printed in an external file\n* v3.0.0: regions support\n* v3.1.0: counties support\n* v3.2.0: cities support\n\nAuthors\n-------\n* **Alessandro Negrini** - *Initial work* - [Github profile](https://github.com/AleNegrini)\n\nSee also the list of [contributors](AUTHORS.rst) who participated in this project.\n\nNotes\n-----\nThis project has been set up using PyScaffold 3.1. For details and usage\ninformation on PyScaffold see https://pyscaffold.org/.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/AleNegrini/PyCristoforo", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "PyCristoforo", "package_url": "https://pypi.org/project/PyCristoforo/", "platform": "", "project_url": "https://pypi.org/project/PyCristoforo/", "project_urls": { "Homepage": "https://github.com/AleNegrini/PyCristoforo" }, "release_url": "https://pypi.org/project/PyCristoforo/2.0.0/", "requires_dist": null, "requires_python": "", "summary": "Python library for the generation of contestualized random coordinates", "version": "2.0.0" }, "last_serial": 5595206, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "913006669f3e9988f0dddc8c715e7e22", "sha256": "0944ecf2c245462545e951cc5c15c521c68cbc475d4ace00837a72549422cfb7" }, "downloads": -1, "filename": "PyCristoforo-1.0.0.post4-py3-none-any.whl", "has_sig": false, "md5_digest": "913006669f3e9988f0dddc8c715e7e22", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 476933, "upload_time": "2019-07-08T20:50:34", "url": "https://files.pythonhosted.org/packages/60/57/df29d7e187e1d1764ba83171e194bd827505188218488332848c97717836/PyCristoforo-1.0.0.post4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4e2b43ac8a1d3d481d95ca1fe65566b9", "sha256": "4dc2c3cb708bb425ac4d5d3a487502eeb1509a2dae6fa52287ea38b6869b1c44" }, "downloads": -1, "filename": "PyCristoforo-1.0.0.post4.tar.gz", "has_sig": false, "md5_digest": "4e2b43ac8a1d3d481d95ca1fe65566b9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 473959, "upload_time": "2019-07-08T20:50:44", "url": "https://files.pythonhosted.org/packages/c6/5a/7b4ceefc85c747249bb1737f28b156f7171996d2899891a159ec5b9fdd40/PyCristoforo-1.0.0.post4.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "a7d814b43b1280ecbeddf6508b9d6e5e", "sha256": "74a2c7593ac57438ad264303ad2c4c58420eb9d6d2d3cdb345b70a2d024fc990" }, "downloads": -1, "filename": "PyCristoforo-1.1.0.post1-py3-none-any.whl", "has_sig": false, "md5_digest": "a7d814b43b1280ecbeddf6508b9d6e5e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7965501, "upload_time": "2019-07-10T17:45:00", "url": "https://files.pythonhosted.org/packages/99/0f/c08eac68e36137737ba16e9b7540c829be02349f3950dc4abbc94fd8f7a6/PyCristoforo-1.1.0.post1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ce64af266ceb527b714c100f39b4beb8", "sha256": "c90fb70481c4ec3494cd0fa41cdc9ad3fd2629ba11504d68bfffd5bd29b00ecf" }, "downloads": -1, "filename": "PyCristoforo-1.1.0.post1.tar.gz", "has_sig": false, "md5_digest": "ce64af266ceb527b714c100f39b4beb8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7460755, "upload_time": "2019-07-10T17:46:48", "url": "https://files.pythonhosted.org/packages/b0/b8/ae3cadfa0fbb0a006eba84461421e230bee7af1ea4b8a24a88eb69995a62/PyCristoforo-1.1.0.post1.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "1dd560b55a9a94f281f75ff122b1045f", "sha256": "cf7ad87c9f76c0b6349e50a3193b2cd798ba9903d7121cd245c73301f430ee87" }, "downloads": -1, "filename": "PyCristoforo-2.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "1dd560b55a9a94f281f75ff122b1045f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7966917, "upload_time": "2019-07-28T08:47:26", "url": "https://files.pythonhosted.org/packages/fd/7a/3ae7fe1692c53a680273683b99495015775636fcc7cc530165ae573fcd43/PyCristoforo-2.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "14ba7f9f254dc99570747291c289b81e", "sha256": "5a2b81d6971bdbb13af91823a12c14b8071e98b3e94b1a9e80c5bfc9ae3700c9" }, "downloads": -1, "filename": "PyCristoforo-2.0.0.tar.gz", "has_sig": false, "md5_digest": "14ba7f9f254dc99570747291c289b81e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7462203, "upload_time": "2019-07-28T08:48:07", "url": "https://files.pythonhosted.org/packages/8c/94/83690116059b3c2feda30566d7fce9fabeed412ae4abc30dc0512524050b/PyCristoforo-2.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "1dd560b55a9a94f281f75ff122b1045f", "sha256": "cf7ad87c9f76c0b6349e50a3193b2cd798ba9903d7121cd245c73301f430ee87" }, "downloads": -1, "filename": "PyCristoforo-2.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "1dd560b55a9a94f281f75ff122b1045f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 7966917, "upload_time": "2019-07-28T08:47:26", "url": "https://files.pythonhosted.org/packages/fd/7a/3ae7fe1692c53a680273683b99495015775636fcc7cc530165ae573fcd43/PyCristoforo-2.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "14ba7f9f254dc99570747291c289b81e", "sha256": "5a2b81d6971bdbb13af91823a12c14b8071e98b3e94b1a9e80c5bfc9ae3700c9" }, "downloads": -1, "filename": "PyCristoforo-2.0.0.tar.gz", "has_sig": false, "md5_digest": "14ba7f9f254dc99570747291c289b81e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7462203, "upload_time": "2019-07-28T08:48:07", "url": "https://files.pythonhosted.org/packages/8c/94/83690116059b3c2feda30566d7fce9fabeed412ae4abc30dc0512524050b/PyCristoforo-2.0.0.tar.gz" } ] }