Usage Guide

This guide covers common use cases and patterns for working with the PyGeoHash library.

Installation

PyGeoHash can be installed from PyPI using pip:

pip install pygeohash

Basic Operations

Encoding Coordinates to Geohash

To convert latitude and longitude coordinates to a geohash string:

import pygeohash as pgh

# Default precision (12 characters)
geohash = pgh.encode(latitude=42.6, longitude=-5.6)
print(geohash)  # 'ezs42e44yx96'

# Custom precision (5 characters)
short_geohash = pgh.encode(latitude=42.6, longitude=-5.6, precision=5)
print(short_geohash)  # 'ezs42'

# Strict encoding (validates input coordinates)
strict_geohash = pgh.encode_strictly(latitude=42.6, longitude=-5.6, precision=5)
print(strict_geohash)  # 'ezs42'

Decoding Geohash to Coordinates

To convert a geohash string back to latitude and longitude coordinates:

import pygeohash as pgh

# Basic decoding
location = pgh.decode(geohash='ezs42')
print(location.latitude, location.longitude)

# Decoding with error margins
exact_location = pgh.decode_exactly(geohash='ezs42')
print(exact_location.latitude, exact_location.longitude)
print(exact_location.latitude_error, exact_location.longitude_error)  # Error margins

Working with Geohash Precision

The precision of a geohash determines how accurately it represents a location. Each additional character in a geohash increases precision:

import pygeohash as pgh

# Different precision levels for the same location
location = (37.371392, -122.046208)  # Google headquarters

for precision in range(1, 13):
    geohash = pgh.encode(location[0], location[1], precision=precision)
    decoded = pgh.decode(geohash)
    print(f"Precision {precision}: {geohash} -> ({decoded.latitude}, {decoded.longitude})")

Calculating Distances

To calculate the distance between two geohashes:

import pygeohash as pgh

# Approximate distance based on matching characters
approx_distance = pgh.geohash_approximate_distance(
    geohash_1='bcd3u',
    geohash_2='bc83n'
)
print(f"Approximate distance: {approx_distance} meters")

# More accurate distance using Haversine formula
haversine_distance = pgh.geohash_haversine_distance(
    geohash_1='bcd3u',
    geohash_2='bc83n'
)
print(f"Haversine distance: {haversine_distance} meters")

Finding Adjacent Geohashes

To find geohashes adjacent to a given geohash:

import pygeohash as pgh

# Get adjacent geohash in a specific direction
# Directions: 'top', 'right', 'bottom', 'left'
adjacent_right = pgh.get_adjacent(geohash='kd3ybyu', direction='right')
print(f"Right: {adjacent_right}")

# Get adjacent geohashes in all four directions
adjacent_top = pgh.get_adjacent(geohash='kd3ybyu', direction='top')
adjacent_right = pgh.get_adjacent(geohash='kd3ybyu', direction='right')
adjacent_bottom = pgh.get_adjacent(geohash='kd3ybyu', direction='bottom')
adjacent_left = pgh.get_adjacent(geohash='kd3ybyu', direction='left')

print(f"Top: {adjacent_top}")
print(f"Right: {adjacent_right}")
print(f"Bottom: {adjacent_bottom}")
print(f"Left: {adjacent_left}")

Bounding Box Operations

PyGeoHash provides functions for working with geospatial bounding boxes:

import pygeohash as pgh

# Get the bounding box for a geohash
geohash = "u4pruyd"
bbox = pgh.get_bounding_box(geohash)

print(f"Bounding box for {geohash}:")
print(f"  Min latitude: {bbox.min_lat}")
print(f"  Min longitude: {bbox.min_lon}")
print(f"  Max latitude: {bbox.max_lat}")
print(f"  Max longitude: {bbox.max_lon}")

Checking if a Point is Within a Box

You can check if a point is within a bounding box:

import pygeohash as pgh

# Define a bounding box
bbox = pgh.BoundingBox(min_lat=40.0, min_lon=-74.0, max_lat=41.0, max_lon=-73.0)

# Check if a point is within the box
point_lat, point_lon = 40.5, -73.5
is_in_box = pgh.is_point_in_box(point_lat, point_lon, bbox)
print(f"Point ({point_lat}, {point_lon}) is {'inside' if is_in_box else 'outside'} the box")

# Check if a point is within a geohash's bounding box
geohash = "dr5r"  # New York area
is_in_geohash = pgh.is_point_in_geohash(point_lat, point_lon, geohash)
print(f"Point ({point_lat}, {point_lon}) is {'inside' if is_in_geohash else 'outside'} the geohash {geohash}")

Checking if Bounding Boxes Intersect

You can check if two bounding boxes intersect:

import pygeohash as pgh

# Define two bounding boxes
box1 = pgh.BoundingBox(min_lat=40.0, min_lon=-74.0, max_lat=41.0, max_lon=-73.0)
box2 = pgh.BoundingBox(min_lat=40.5, min_lon=-73.5, max_lat=41.5, max_lon=-72.5)

# Check if they intersect
do_intersect = pgh.do_boxes_intersect(box1, box2)
print(f"Boxes {'intersect' if do_intersect else 'do not intersect'}")

Finding Geohashes in a Bounding Box

You can find all geohashes that intersect with a bounding box:

import pygeohash as pgh

# Define a bounding box
bbox = pgh.BoundingBox(min_lat=40.0, min_lon=-74.0, max_lat=40.1, max_lon=-73.9)

# Find geohashes that intersect with the box
geohashes = pgh.geohashes_in_box(bbox, precision=5)
print(f"Found {len(geohashes)} geohashes at precision 5")
print(geohashes)

# Try with a different precision
geohashes_p6 = pgh.geohashes_in_box(bbox, precision=6)
print(f"Found {len(geohashes_p6)} geohashes at precision 6")

Practical Example: Geospatial Querying

Using bounding boxes for efficient geospatial querying:

import pygeohash as pgh

# Sample database of locations with their coordinates
locations = [
    {"id": 1, "name": "Central Park", "lat": 40.785091, "lon": -73.968285},
    {"id": 2, "name": "Empire State Building", "lat": 40.748817, "lon": -73.985428},
    {"id": 3, "name": "Statue of Liberty", "lat": 40.689247, "lon": -74.044502},
    {"id": 4, "name": "Times Square", "lat": 40.758896, "lon": -73.985130},
    {"id": 5, "name": "Brooklyn Bridge", "lat": 40.706086, "lon": -73.996864},
]

# Define a search area (bounding box)
search_area = pgh.BoundingBox(
    min_lat=40.7, min_lon=-74.0,
    max_lat=40.8, max_lon=-73.9
)

# Find locations within the search area
results = []
for location in locations:
    if pgh.is_point_in_box(location["lat"], location["lon"], search_area):
        results.append(location)

print(f"Found {len(results)} locations within the search area:")
for location in results:
    print(f"  - {location['name']}")

# Alternative approach using geohashes
# First, find all geohashes in the search area at precision 5
geohashes_in_area = pgh.geohashes_in_box(search_area, precision=5)

# Pre-compute geohashes for all locations
for location in locations:
    location["geohash"] = pgh.encode(location["lat"], location["lon"], precision=5)

# Find locations with matching geohashes
geohash_results = [
    location for location in locations
    if location["geohash"] in geohashes_in_area
]

print(f"Found {len(geohash_results)} locations using geohash matching:")
for location in geohash_results:
    print(f"  - {location['name']} (geohash: {location['geohash']})")

Statistical Functions

PyGeoHash provides several statistical functions for working with groups of geohashes:

import pygeohash as pgh

# Sample geohashes
geohashes = ['ezs42', 'ezs41', 'ezs43', 'ezs40']

# Find the mean position
mean_position = pgh.mean(geohashes)
print(f"Mean position: {mean_position}")

# Find cardinal extremes
north = pgh.northern(geohashes)
south = pgh.southern(geohashes)
east = pgh.eastern(geohashes)
west = pgh.western(geohashes)

print(f"Northernmost: {north}")
print(f"Southernmost: {south}")
print(f"Easternmost: {east}")
print(f"Westernmost: {west}")

# Calculate statistical measures
variance = pgh.variance(geohashes)
std_dev = pgh.std(geohashes)

print(f"Variance: {variance} meters²")
print(f"Standard deviation: {std_dev} meters")

Practical Examples

Geofencing

Using geohashes for simple geofencing:

import pygeohash as pgh

# Define a geofence as a set of geohash prefixes
geofence = {"u09t", "u09s", "u09w"}  # Area around Paris

# Check if a location is within the geofence
def is_in_geofence(lat, lng, geofence_prefixes, prefix_length=4):
    location_geohash = pgh.encode(lat, lng, precision=prefix_length)
    location_prefix = location_geohash[:4]
    return location_prefix in geofence_prefixes

# Test locations
test_locations = [
    {"name": "Eiffel Tower", "lat": 48.8584, "lng": 2.2945},
    {"name": "Notre-Dame", "lat": 48.8530, "lng": 2.3499},
    {"name": "London Eye", "lat": 51.5033, "lng": -0.1195},
]

for location in test_locations:
    in_geofence = is_in_geofence(location["lat"], location["lng"], geofence)
    print(f"{location['name']} is {'inside' if in_geofence else 'outside'} the geofence")

Visualization

PyGeoHash provides visualization capabilities through the optional viz module. To use these functions, you need to install the visualization dependencies:

pip install pygeohash[viz]

Plotting a Single Geohash

import pygeohash as pgh
from pygeohash.viz import plot_geohash
import matplotlib.pyplot as plt

# Encode a location to a geohash
geohash = pgh.encode(37.7749, -122.4194, precision=6)  # San Francisco

# Plot the geohash
fig, ax = plot_geohash(geohash, color="red", alpha=0.5)
plt.title(f"Geohash: {geohash}")
plt.show()
Single geohash visualization

Plotting Multiple Geohashes

import pygeohash as pgh
from pygeohash.viz import plot_geohashes
import matplotlib.pyplot as plt

# Define some locations
locations = {
    "San Francisco": (37.7749, -122.4194),
    "Oakland": (37.8044, -122.2711),
    "Berkeley": (37.8715, -122.2730),
    "San Jose": (37.3382, -121.8863)
}

# Encode each location to a geohash
geohashes = [pgh.encode(lat, lng, precision=6) for name, (lat, lng) in locations.items()]

# Plot the geohashes with labels
fig, ax = plot_geohashes(
    geohashes,
    labels=list(locations.keys()),
    show_labels=True,
    colors=["red", "blue", "green", "orange"]
)
plt.title("Bay Area Locations")
plt.show()
Multiple geohashes with labels

Creating Interactive Maps

PyGeoHash integrates with Folium to create interactive maps:

import pygeohash as pgh
from pygeohash.viz import folium_map

# Create a map centered on a location
m = folium_map(center=(37.7749, -122.4194), zoom_start=12)

# Add geohashes to the map
geohash = pgh.encode(37.7749, -122.4194, precision=6)
m.add_geohash(geohash, color="red", popup="San Francisco")

# Add a grid of geohashes at precision 5
m.add_geohash_grid(precision=5, fill_opacity=0.2)

# Save the map to an HTML file
m.save("map.html")

For more detailed examples of visualization, see the Examples section.

Performance Considerations

  • Geohash operations are very fast due to the high-performance C extension implementation

  • When working with millions of geohashes, consider using a database with geospatial capabilities

  • For high-precision applications, be aware of the limitations of geohashes near poles and the 180° meridian

  • Visualization functions may be slower for large numbers of geohashes; consider limiting the number of geohashes displayed or using a lower precision

For more detailed examples of visualization, see the Examples section.

Performance Considerations

  • Geohash operations are very fast due to the high-performance C extension implementation

  • When working with millions of geohashes, consider using a database with geospatial capabilities

  • For high-precision applications, be aware of the limitations of geohashes near poles and the 180° meridian

  • Visualization functions may be slower for large numbers of geohashes; consider limiting the number of geohashes displayed or using a lower precision