{"id":28376976,"url":"https://github.com/bellingcat/shadowfinder","last_synced_at":"2025-06-26T18:32:08.552Z","repository":{"id":237539791,"uuid":"794680486","full_name":"bellingcat/ShadowFinder","owner":"bellingcat","description":"Find possible locations of shadows around the world","archived":false,"fork":false,"pushed_at":"2025-06-12T16:47:11.000Z","size":1073,"stargazers_count":479,"open_issues_count":11,"forks_count":39,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-12T17:34:34.696Z","etag":null,"topics":["command-line","geolocation","notebook","open-source-research","python"],"latest_commit_sha":null,"homepage":"https://colab.research.google.com/github/Bellingcat/ShadowFinder/blob/main/ShadowFinderColab.ipynb","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bellingcat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-05-01T18:14:57.000Z","updated_at":"2025-06-03T16:46:18.000Z","dependencies_parsed_at":"2025-05-12T06:45:52.331Z","dependency_job_id":null,"html_url":"https://github.com/bellingcat/ShadowFinder","commit_stats":null,"previous_names":["galenreich/shadowfinder","bellingcat/shadowfinder"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/bellingcat/ShadowFinder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bellingcat%2FShadowFinder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bellingcat%2FShadowFinder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bellingcat%2FShadowFinder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bellingcat%2FShadowFinder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bellingcat","download_url":"https://codeload.github.com/bellingcat/ShadowFinder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bellingcat%2FShadowFinder/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260200875,"owners_count":22973772,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line","geolocation","notebook","open-source-research","python"],"created_at":"2025-05-30T00:38:51.841Z","updated_at":"2025-06-26T18:32:08.497Z","avatar_url":"https://github.com/bellingcat.png","language":"Python","readme":"# ShadowFinder\n\n\u003ca href=\"https://www.bellingcat.com\"\u003e\u003cimg alt=\"Bellingcat logo: Discover Bellingcat\" src=\"https://img.shields.io/badge/Discover%20Bellingcat-%20?style=for-the-badge\u0026logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAYCAYAAADKx8xXAAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0UqDnZQEcxQneyiIo6likWwUNoKrTqYXPoFTRqSFBdHwbXg4Mdi1cHFWVcHV0EQ%2FABxdnBSdJES%2F5cUWsR4cNyPd%2Fced%2B8AoVllqtkTA1TNMtKJuJjLr4rBVwQwhhBEDEvM1JOZxSw8x9c9fHy9i%2FIs73N%2Fjn6lYDLAJxLHmG5YxBvEs5uWznmfOMzKkkJ8Tjxp0AWJH7kuu%2FzGueSwwDPDRjY9TxwmFktdLHcxKxsq8QxxRFE1yhdyLiuctzir1Tpr35O%2FMFTQVjJcpzmKBJaQRIo6klFHBVVYiNKqkWIiTftxD%2F%2BI40%2BRSyZXBYwcC6hBheT4wf%2Fgd7dmcXrKTQrFgcCLbX%2BMA8FdoNWw7e9j226dAP5n4Err%2BGtNYO6T9EZHixwBA9vAxXVHk%2FeAyx1g6EmXDMmR%2FDSFYhF4P6NvygODt0Dfmttbex%2BnD0CWulq%2BAQ4OgYkSZa97vLu3u7d%2Fz7T7%2BwHEU3LHAa%2FQ6gAAAAZiS0dEAAAAAAAA%2BUO7fwAAAAlwSFlzAAAuIwAALiMBeKU%2FdgAAAAd0SU1FB%2BgFHwwiMH4odB4AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAA50lEQVQ4y82SvWpCQRCFz25ERSJiCNqlUiS1b5AuEEiZIq1NOsGXCKms0wXSp9T6dskDiFikyiPc%2FrMZyf3FXSGQ0%2BzuzPl2ZoeVKgQ0gQ2wBVpVHlcDkjM5V%2FJ5nag6sJ%2FZX%2Bh%2FC7gEhqeAFKf7p1M9aB3b5oN1OomB7g1axUBPBr3GQHODHmOgqUF3MZAzKI2d4LWBV4H%2BMXDuJd1a7Cew1k7SwksaHC4LqNaw7aeX9GWHXkC1G1sTAS17Y3Kk2lnp4wNLiz0DrgLq8qt2MfmSSabAO%2FBBXp26dtrADPjOmN%2BAUdG7B3cE61l5hOZiAAAAAElFTkSuQmCC\u0026logoColor=%23fff\u0026color=%23000\"\u003e\u003c/a\u003e\u003c!--\n--\u003e\u003ca href=\"https://discord.gg/bellingcat\"\u003e\u003cimg alt=\"Discord logo: Join our community\" src=\"https://img.shields.io/badge/Join%20our%20community-%20?style=for-the-badge\u0026logo=discord\u0026logoColor=%23fff\u0026color=%235865F2\"\u003e\u003c/a\u003e\u003c!--\n--\u003e\u003ca href=\"https://colab.research.google.com/github/Bellingcat/ShadowFinder/blob/main/ShadowFinderColab.ipynb\"\u003e\u003cimg alt=\"Colab icon: Try it on Colab\" src=\"https://img.shields.io/badge/Try%20it%20on%20Colab-%20?style=for-the-badge\u0026logo=googlecolab\u0026logoColor=fff\u0026logoSize=auto\u0026color=e8710a\"\u003e\u003c/a\u003e\n\nA lightweight tool and Google Colab notebook for estimating the points on the Earth's surface where a shadow of a particular length could occur, for geolocation purposes.\n\nUsing an object's height, the length of its shadow, the date and the time, ShadowFinder estimates the possible locations where that shadow could occur. These possible locations are shown as a bright band on a map of the Earth:\n\n![ExampleShadowFinderOutput](https://github.com/user-attachments/assets/1620de90-3544-4678-856a-9ac5a56655a4)\n\n\n## Usage - Google Colab Notebook 🚀\nNo installation necessary, just try it out using the [Google Colab notebook here](https://colab.research.google.com/github/Bellingcat/ShadowFinder/blob/main/ShadowFinderColab.ipynb)!\n\n## Installation :magic_wand:\n[![PyPI - Version](https://img.shields.io/pypi/v/ShadowFinder)](https://pypi.org/project/ShadowFinder/)\n\nShadowFinder is built with the interactive notebook in mind, which can be downloaded and used in a local Jupyter environment, the package also provides a Python API and a command-line interface.\n\nShadowFinder is published on [PyPi](https://pypi.org/project/ShadowFinder/) so can be installed via `pip` with:\n\n```shell\npip install shadowfinder\n```\n## Usage - Python Library 🐍\n\nIf you want to use ShadowFinder directly from Python, the usage is as follows.\n\n```python\nfrom shadowfinder import ShadowFinder\n\nfinder = ShadowFinder()\n\n# Use a pre-generated timezone grid to save time\n# Attempt to load a timezone grid and on a failure generate the grid and save to file\ntry:\n    finder.load_timezone_grid()\nexcept FileNotFoundError:\n    finder.generate_timezone_grid()\n    finder.save_timezone_grid() # timezone_grid.json\n\n# Set up the scenario\n# Provide either object_height and shadow_length OR sun_altitude_angle\nfinder.set_details(\n    date_time=date_time, # datetime object with no timezone awareness\n    object_height=object_height, # object height in arbitrary units\n    shadow_length=shadow_length, # shadow length in arbitrary units\n    time_format=time_type, # string, either 'local' or 'utc'\n    sun_altitude_angle=sun_altitude_angle, # altitude angle of the sun, in degrees above the horizon\n)\n\n# Run the finder\nfinder.find_shadows()\n\n# Access the resulting figure\nfig = finder.plot_shadows()\n```\n\n## Usage - Command Line Interface 🐌\n\u003e[!IMPORTANT]\n\u003e Using the CLI is not the recommended way of using ShadowFinder as it is quite slow (there is currently not a caching strategy for the timezone_grid, so this is generated every run which is resource intesive)\n\n```shell\nshadowfinder find 10 5 2024-02-29 13:59:59 --time_format=utc\n```\nWhere the arguments are `OBJECT_HEIGHT`, `SHADOW_LENGTH`, `DATE`, and `TIME` respectively.\n\nYou can also use the angle to the sun directly (above the horizon, in degrees):\n\n```shell\nshadowfinder find_sun 50 2024-02-29 13:59:59 --time_format=utc\n```\nWhere the arguments are `SUN_ALTITUDE_ANGLE`, `DATE`, and `TIME` respectively.\n\nMore complete help information can be found by running:\n\n```shell\nshadowfinder find --help\nshadowfinder find_sun --help\n```\n\n## Development :octocat:\n\n\u003cdetails\u003e\n\u003csummary\u003eExpand to view information for developers\u003c/summary\u003e\n\nThis section describes how to install the project to run it from source, for example if you want to build new features.\n\n```bash\n# Clone the repository\ngit clone https://github.com/bellingcat/ShadowFinder.git\n\n# Change directory to the project folder\ncd ShadowFinder\n```\n\nThis project uses [Poetry](https://python-poetry.org/docs) for dependency management and packaging.\n\n```bash\n# Install poetry if you haven't already\npip install poetry\n\n# Install dependencies\npoetry install\n\n# Setup pre-commit hooks\npoetry run pre-commit install\n\n# Run the tool\npoetry run shadowfinder --help\n\n# Run tests against your current Python interpreter\npoetry run pytest\n\n# Or, run pytest against all shadowfinder supported Python versions\npoetry run tox p  # p=run in parallel\n```\n\u003c/details\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbellingcat%2Fshadowfinder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbellingcat%2Fshadowfinder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbellingcat%2Fshadowfinder/lists"}