Grid System Enhancements Example.

This example demonstrates the new grid system enhancements in M3S: 1. What3Words integration 2. Grid conversion utilities 3. Grid cell relationship analysis 4. Multi-resolution grid operations

  • M3S Grid System Enhancements Demo, Grid Systems Comparison, Default Cell Areas by Grid System, Multi-Resolution Grid (Geohash), Cell Adjacency Matrix
  • Grid Conversion Analysis, Distribution of Conversion Methods, Conversions by Precision Level
M3S Grid System Enhancements Demo
==================================================

=== What3Words Grid System ===
What3Words cell area: 9e-06 km²
NYC What3Words cell: w3w.wde.we7.w3b
Cell area: 0.000008985 km²
Number of neighbors: 8
Neighbor identifiers: ['w3w.wdd.w96.w79...', 'w3w.w30.w77.w1b...', 'w3w.w07.w28.w10...']

=== Grid Conversion Utilities ===
Available grid systems:
    system  default_precision  default_area_km2
0  geohash                  5       4892.000000
1     mgrs                  1        100.000000
2       h3                  7          5.160000
3  quadkey                 12         95.725395
4       s2                 10         81.073761

Source Geohash cell: dr5re
Source cell area: 18.11 km²

Conversions:
  H3: 872a1072effffff
  Quadkey: 032010110123
  What3Words: w3w.w15.w07.wbf

Conversion table (Geohash -> H3): 2 mappings
  source_system source_id  source_precision target_system        target_id  target_precision conversion_method
0       geohash     dr5re                 5            h3  872a1072effffff                 7          centroid
1       geohash     dr5rs                 5            h3  872a1072dffffff                 7          centroid

=== Grid Cell Relationship Analysis ===
Analyzing relationships for 4 cells
Relationship between first two cells: touches
Adjacent cells to first cell: 3

Adjacency matrix:
        dr5rs5  dr5reg  dr5rsh  dr5reu
dr5rs5       0       1       1       1
dr5reg       1       0       1       1
dr5rsh       1       1       0       1
dr5reu       1       1       1       0
Network connectivity: 1.000

=== Multi-Resolution Grid Operations ===
Multi-resolution grid with 4 levels
Resolution levels:
   level  precision  area_km2
0      0          4   39135.0
1      1          5    4892.0
2      2          6    1223.0
3      3          7     153.0

Hierarchical cells for NYC:
  Precision 4: dr5r (579.69 km²)
  Precision 5: dr5re (18.11 km²)
  Precision 6: dr5reg (0.57 km²)
  Precision 7: dr5regw (0.02 km²)

Scale transitions:
   from_precision  to_precision  subdivision_ratio
0               4             5                2.0
1               5             6               15.0
2               6             7               23.0

Adaptive grid contains 120 cells
Cells by precision level:
  Precision 5: 120 cells

=== Combined Visualization Example ===
/home/runner/work/m3s/m3s/examples/grid_enhancements_example.py:178: DeprecationWarning: The 'resolution' parameter is deprecated. Use 'precision' instead.
  h3_grid = H3Grid(resolution=9)
Geohash cells: 32
H3 cells: 59
Converted 5 Geohash cells to 10 H3 cells
Found 15 adjacent cell pairs in sample of 10 cells
Visualization example completed!

=== Creating Grid System Comparison Plots ===
/home/runner/work/m3s/m3s/examples/grid_enhancements_example.py:237: DeprecationWarning: The 'resolution' parameter is deprecated. Use 'precision' instead.
  "H3": H3Grid(resolution=9),
/home/runner/work/m3s/m3s/examples/grid_enhancements_example.py:238: DeprecationWarning: The 'level' parameter is deprecated. Use 'precision' instead.
  "Quadkey": QuadkeyGrid(level=15),
Plots saved as 'grid_enhancements_demo.png'

=== Creating Grid Conversion Analysis Plots ===
Conversion analysis plots saved as 'conversion_analysis.png'

All demonstrations completed successfully!

Key features demonstrated:
✓ What3Words grid integration with 3m precision
✓ Grid conversion between different systems
✓ Spatial relationship analysis (containment, adjacency)
✓ Multi-resolution grid operations with adaptive selection
✓ Combined workflows using multiple enhancement features
✓ Comprehensive visualizations and plots

import geopandas as gpd
import matplotlib.pyplot as plt
import numpy as np
from shapely.geometry import Point

from m3s import (
    GeohashGrid,
    H3Grid,
    QuadkeyGrid,
    What3WordsGrid,
    analyze_relationship,
    convert_cell,
    create_adaptive_grid,
    create_adjacency_matrix,
    create_conversion_table,
    create_multiresolution_grid,
    find_adjacent_cells,
    list_grid_systems,
)


def demonstrate_what3words():
    """Demonstrate What3Words grid integration."""
    print("=== What3Words Grid System ===")

    # Create What3Words grid
    w3w_grid = What3WordsGrid()
    print(f"What3Words cell area: {w3w_grid.area_km2} km²")

    # Get cell for NYC coordinates
    nyc_cell = w3w_grid.get_cell_from_point(40.7128, -74.0060)
    print(f"NYC What3Words cell: {nyc_cell.identifier}")
    print(f"Cell area: {nyc_cell.area_km2:.9f} km²")

    # Find neighbors
    neighbors = w3w_grid.get_neighbors(nyc_cell)
    print(f"Number of neighbors: {len(neighbors)}")
    print("Neighbor identifiers:", [n.identifier[:20] + "..." for n in neighbors[:3]])

    print()


def demonstrate_grid_conversion():
    """Demonstrate grid conversion utilities."""
    print("=== Grid Conversion Utilities ===")

    # List available grid systems
    systems_info = list_grid_systems()
    print("Available grid systems:")
    print(systems_info[["system", "default_precision", "default_area_km2"]].head())
    print()

    # Create source cell (Geohash)
    geohash_grid = GeohashGrid(precision=5)
    source_cell = geohash_grid.get_cell_from_point(40.7128, -74.0060)
    print(f"Source Geohash cell: {source_cell.identifier}")
    print(f"Source cell area: {source_cell.area_km2:.2f} km²")

    # Convert to different systems
    h3_cell = convert_cell(source_cell, "h3", method="centroid")
    quadkey_cell = convert_cell(source_cell, "quadkey", method="centroid")
    w3w_cell = convert_cell(source_cell, "what3words", method="centroid")

    print("\nConversions:")
    print(f"  H3: {h3_cell.identifier}")
    print(f"  Quadkey: {quadkey_cell.identifier}")
    print(f"  What3Words: {w3w_cell.identifier}")

    # Create conversion table for small area
    bounds = (-74.01, 40.71, -74.00, 40.72)
    conversion_table = create_conversion_table(
        "geohash", "h3", bounds, source_precision=5, target_precision=7
    )
    print(f"\nConversion table (Geohash -> H3): {len(conversion_table)} mappings")
    print(conversion_table.head())

    print()


def demonstrate_relationship_analysis():
    """Demonstrate grid cell relationship analysis."""
    print("=== Grid Cell Relationship Analysis ===")

    # Create test cells
    geohash_grid = GeohashGrid(precision=6)

    # Get cells in a small region
    cells = geohash_grid.get_cells_in_bbox(40.71, -74.01, 40.72, -74.00)
    print(f"Analyzing relationships for {len(cells)} cells")

    if len(cells) >= 2:
        # Analyze relationship between first two cells
        relationship = analyze_relationship(cells[0], cells[1])
        print(f"Relationship between first two cells: {relationship.value}")

        # Find adjacent cells to the first cell
        adjacent = find_adjacent_cells(cells[0], cells[1:])
        print(f"Adjacent cells to first cell: {len(adjacent)}")

        # Create adjacency matrix (limit to first 5 cells for readability)
        sample_cells = cells[: min(5, len(cells))]
        adj_matrix = create_adjacency_matrix(sample_cells)
        print("\nAdjacency matrix:")
        print(adj_matrix)

        # Calculate connectivity
        total_connections = adj_matrix.sum().sum()
        max_connections = len(sample_cells) * (len(sample_cells) - 1)
        connectivity = total_connections / max_connections if max_connections > 0 else 0
        print(f"Network connectivity: {connectivity:.3f}")

    print()


def demonstrate_multiresolution():
    """Demonstrate multi-resolution grid operations."""
    print("=== Multi-Resolution Grid Operations ===")

    # Create multi-resolution grid with Geohash
    base_grid = GeohashGrid(precision=5)
    resolution_levels = [4, 5, 6, 7]  # Coarse to fine

    multi_grid = create_multiresolution_grid(base_grid, resolution_levels)
    print(f"Multi-resolution grid with {len(resolution_levels)} levels")

    # Get resolution statistics
    stats = multi_grid.get_resolution_statistics()
    print("Resolution levels:")
    print(stats[["level", "precision", "area_km2"]])

    # Get hierarchical cells for NYC
    nyc_point = Point(-74.0060, 40.7128)
    hierarchical_cells = multi_grid.get_hierarchical_cells(nyc_point)

    print("\nHierarchical cells for NYC:")
    for precision, cell in hierarchical_cells.items():
        print(f"  Precision {precision}: {cell.identifier} ({cell.area_km2:.2f} km²)")

    # Populate region and analyze scale transitions
    bounds = (-74.02, 40.70, -73.98, 40.73)
    multi_grid.populate_region(bounds)

    transitions = multi_grid.analyze_scale_transitions(bounds)
    print("\nScale transitions:")
    print(transitions[["from_precision", "to_precision", "subdivision_ratio"]])

    # Create adaptive grid
    adaptive_gdf = create_adaptive_grid(base_grid, bounds, resolution_levels)
    print(f"\nAdaptive grid contains {len(adaptive_gdf)} cells")
    if len(adaptive_gdf) > 0:
        precision_counts = adaptive_gdf["precision"].value_counts().sort_index()
        print("Cells by precision level:")
        for precision, count in precision_counts.items():
            print(f"  Precision {precision}: {count} cells")

    print()


def create_visualization_example():
    """Create a visualization example combining multiple enhancements."""
    print("=== Combined Visualization Example ===")

    # Define NYC area
    bounds = (-74.02, 40.70, -73.98, 40.73)

    # Create different grid systems
    geohash_grid = GeohashGrid(precision=6)
    h3_grid = H3Grid(resolution=9)

    # Get cells from each system
    geohash_cells = geohash_grid.get_cells_in_bbox(*bounds)
    h3_cells = h3_grid.get_cells_in_bbox(*bounds)

    print(f"Geohash cells: {len(geohash_cells)}")
    print(f"H3 cells: {len(h3_cells)}")

    # Convert some geohash cells to H3
    if geohash_cells:
        converted_cells = []
        for cell in geohash_cells[:5]:  # Convert first 5
            h3_converted = convert_cell(cell, "h3", method="overlap")
            if isinstance(h3_converted, list):
                converted_cells.extend(h3_converted)
            else:
                converted_cells.append(h3_converted)

        print(
            f"Converted {len(geohash_cells[:5])} Geohash cells to {len(converted_cells)} H3 cells"
        )

    # Analyze relationships within H3 cells
    if len(h3_cells) > 1:
        adjacent_pairs = 0
        sample_cells = h3_cells[: min(10, len(h3_cells))]

        for i, cell1 in enumerate(sample_cells):
            for _j, cell2 in enumerate(sample_cells[i + 1 :], i + 1):
                rel = analyze_relationship(cell1, cell2)
                if rel.value in ["touches", "adjacent"]:
                    adjacent_pairs += 1

        print(
            f"Found {adjacent_pairs} adjacent cell pairs in sample of {len(sample_cells)} cells"
        )

    print("Visualization example completed!")
    print()


def plot_grid_comparison():
    """Create plots comparing different grid systems."""
    print("=== Creating Grid System Comparison Plots ===")

    # Define a small area for visualization
    center_lat, center_lon = 40.7128, -74.0060
    offset = 0.01  # Small area around NYC
    bounds = (
        center_lon - offset,
        center_lat - offset,
        center_lon + offset,
        center_lat + offset,
    )

    # Create different grid systems with similar cell sizes
    grids = {
        "Geohash": GeohashGrid(precision=7),
        "H3": H3Grid(resolution=9),
        "Quadkey": QuadkeyGrid(level=15),
    }

    # Create subplot figure
    fig, axes = plt.subplots(2, 2, figsize=(15, 12))
    fig.suptitle("M3S Grid System Enhancements Demo", fontsize=16, fontweight="bold")

    # Plot 1: Grid system comparison
    ax1 = axes[0, 0]
    ax1.set_title("Grid Systems Comparison")
    ax1.set_xlabel("Longitude")
    ax1.set_ylabel("Latitude")

    colors = ["red", "blue", "green"]
    alphas = [0.3, 0.3, 0.3]

    for i, (name, grid) in enumerate(grids.items()):
        cells = grid.get_cells_in_bbox(*bounds)
        if cells:
            # Create GeoDataFrame for plotting
            cell_data = []
            for cell in cells[:20]:  # Limit for visibility
                cell_data.append({"geometry": cell.polygon, "system": name})

            if cell_data:
                gdf = gpd.GeoDataFrame(cell_data)
                gdf.boundary.plot(
                    ax=ax1, color=colors[i], alpha=alphas[i], linewidth=1, label=name
                )

    ax1.legend()
    ax1.set_xlim(bounds[0], bounds[2])
    ax1.set_ylim(bounds[1], bounds[3])
    ax1.grid(True, alpha=0.3)

    # Plot 2: Cell area comparison
    ax2 = axes[0, 1]
    systems_info = list_grid_systems()
    if len(systems_info) > 0:
        # Filter to systems we can actually use
        plot_systems = systems_info[
            systems_info["system"].isin(["geohash", "h3", "quadkey", "mgrs"])
        ].copy()

        if len(plot_systems) > 0:
            ax2.bar(plot_systems["system"], plot_systems["default_area_km2"])
            ax2.set_title("Default Cell Areas by Grid System")
            ax2.set_xlabel("Grid System")
            ax2.set_ylabel("Area (km²)")
            ax2.set_yscale("log")
            plt.setp(ax2.get_xticklabels(), rotation=45)

    # Plot 3: Multi-resolution demonstration
    ax3 = axes[1, 0]
    ax3.set_title("Multi-Resolution Grid (Geohash)")
    ax3.set_xlabel("Longitude")
    ax3.set_ylabel("Latitude")

    # Create multi-resolution grid
    base_grid = GeohashGrid(precision=5)
    multi_grid = create_multiresolution_grid(base_grid, [5, 6, 7])

    colors_multi = ["red", "orange", "yellow"]
    alphas_multi = [0.6, 0.4, 0.2]

    level_cells = multi_grid.populate_region(bounds)
    for i, (precision, cells) in enumerate(level_cells.items()):
        if cells:
            cell_data = []
            for cell in cells[:15]:  # Limit for visibility
                cell_data.append({"geometry": cell.polygon, "precision": precision})

            if cell_data:
                gdf = gpd.GeoDataFrame(cell_data)
                gdf.boundary.plot(
                    ax=ax3,
                    color=colors_multi[i],
                    alpha=alphas_multi[i],
                    linewidth=2 - i * 0.5,
                    label=f"Precision {precision}",
                )

    ax3.legend()
    ax3.set_xlim(bounds[0], bounds[2])
    ax3.set_ylim(bounds[1], bounds[3])
    ax3.grid(True, alpha=0.3)

    # Plot 4: Adjacency matrix heatmap
    ax4 = axes[1, 1]
    ax4.set_title("Cell Adjacency Matrix")

    # Get a small sample of cells for adjacency analysis
    sample_grid = GeohashGrid(precision=8)
    sample_cells = sample_grid.get_cells_in_bbox(
        center_lat - 0.005, center_lon - 0.005, center_lat + 0.005, center_lon + 0.005
    )

    if len(sample_cells) > 1:
        # Limit to reasonable number for visualization
        sample_cells = sample_cells[: min(8, len(sample_cells))]
        adj_matrix = create_adjacency_matrix(sample_cells)

        # Convert to numpy array for plotting
        matrix_values = adj_matrix.values

        im = ax4.imshow(matrix_values, cmap="Blues", aspect="auto")
        ax4.set_xticks(range(len(sample_cells)))
        ax4.set_yticks(range(len(sample_cells)))
        ax4.set_xticklabels(
            [cell.identifier[-4:] for cell in sample_cells], rotation=45
        )
        ax4.set_yticklabels([cell.identifier[-4:] for cell in sample_cells])

        # Add colorbar
        plt.colorbar(im, ax=ax4)
    else:
        ax4.text(
            0.5,
            0.5,
            "Insufficient cells\nfor adjacency analysis",
            ha="center",
            va="center",
            transform=ax4.transAxes,
        )

    plt.tight_layout()
    plt.savefig("grid_enhancements_demo.png", dpi=150, bbox_inches="tight")
    print("Plots saved as 'grid_enhancements_demo.png'")
    plt.show()
    print()


def plot_conversion_analysis():
    """Create plots showing grid conversion analysis."""
    print("=== Creating Grid Conversion Analysis Plots ===")

    # Define analysis area
    bounds = (-74.01, 40.71, -74.00, 40.72)

    # Create conversion table
    try:
        conversion_table = create_conversion_table(
            "geohash", "h3", bounds, source_precision=6, target_precision=9
        )

        if len(conversion_table) > 0:
            fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
            fig.suptitle("Grid Conversion Analysis", fontsize=14, fontweight="bold")

            # Plot 1: Conversion method distribution
            method_counts = conversion_table["conversion_method"].value_counts()
            ax1.pie(method_counts.values, labels=method_counts.index, autopct="%1.1f%%")
            ax1.set_title("Distribution of Conversion Methods")

            # Plot 2: Precision level comparison
            precision_data = (
                conversion_table.groupby(["source_precision", "target_precision"])
                .size()
                .reset_index(name="count")
            )

            if len(precision_data) > 0:
                x_pos = np.arange(len(precision_data))
                ax2.bar(x_pos, precision_data["count"])
                ax2.set_title("Conversions by Precision Level")
                ax2.set_xlabel("Source -> Target Precision")
                ax2.set_ylabel("Number of Conversions")

                labels = [
                    f"{row['source_precision']}->{row['target_precision']}"
                    for _, row in precision_data.iterrows()
                ]
                ax2.set_xticks(x_pos)
                ax2.set_xticklabels(labels)

            plt.tight_layout()
            plt.savefig("conversion_analysis.png", dpi=150, bbox_inches="tight")
            print("Conversion analysis plots saved as 'conversion_analysis.png'")
            plt.show()
        else:
            print("No conversion data available for plotting")

    except Exception as e:
        print(f"Could not create conversion analysis plots: {e}")

    print()


def main():
    """Main function to run all demonstrations."""
    print("M3S Grid System Enhancements Demo")
    print("=" * 50)
    print()

    demonstrate_what3words()
    demonstrate_grid_conversion()
    demonstrate_relationship_analysis()
    demonstrate_multiresolution()
    create_visualization_example()

    # Create visualizations
    plot_grid_comparison()
    plot_conversion_analysis()

    print("All demonstrations completed successfully!")
    print("\nKey features demonstrated:")
    print("✓ What3Words grid integration with 3m precision")
    print("✓ Grid conversion between different systems")
    print("✓ Spatial relationship analysis (containment, adjacency)")
    print("✓ Multi-resolution grid operations with adaptive selection")
    print("✓ Combined workflows using multiple enhancement features")
    print("✓ Comprehensive visualizations and plots")


if __name__ == "__main__":
    main()

Total running time of the script: (0 minutes 5.005 seconds)

Gallery generated by Sphinx-Gallery