Skip to content

Conversion Module

The conversion module provides comprehensive functions to convert between different coordinate systems, geographic data formats, and discrete global grid systems (DGGS).

Overview

The conversion module supports multiple types of conversions:

  • Latitude/Longitude to DGGS: Convert lat/lon coordinates to various DGGS cell IDs
  • DGGS to GeoJSON: Convert DGGS cell IDs to GeoJSON features
  • Vector to DGGS: Convert vector geometries to DGGS cells
  • DGGS Compact: Compact/ Expand DGGS cells
  • Raster to DGGS: Convert raster data to DGGS cells
  • DGGAL Conversions: Use the external dgg CLI to convert DGGAL ZoneIDs and lat/lon

Supported DGGS Systems

The module supports the following discrete global grid systems:

  • H3: Uber's hexagonal hierarchical geospatial indexing system
  • S2: Google's spherical geometry library
  • A5: Pentagonal DGGS
  • RHEALPix: Equal-area hierarchical triangular mesh
  • ISEA4T: Icosahedral Snyder Equal Area Aperture 4 Triangle
  • ISEA3H: Icosahedral Snyder Equal Area Aperture 3 Hexagon
  • EASE: Equal-Area Scalable Earth Grid
  • QTM: Quaternary Triangular Mesh
  • OLC: Open Location Code (Plus Codes)
  • Geohash: Hierarchical spatial data structure
  • GEOREF: World Geographic Reference System
  • MGRS: Military Grid Reference System
  • Tilecode: Hierarchical tiling system
  • Quadkey: Microsoft's hierarchical spatial index
  • Maidenhead: Amateur radio grid square system
  • GARS: Global Area Reference System
  • DGGAL: External DGGS family accessed via the dgg CLI (e.g., GNOSIS, ISEA3H/9R, IVEA3H/9R, RTEA3H/9R, RHEALPix)

DGGAL Usage

Lat/Lon to DGGAL ZoneID

1
2
3
4
from vgrid.conversion.latlon2dggs import latlon2dggal

# Compute a DGGAL ZoneID (requires `dgg` on PATH)
zone_id = latlon2dggal("isea3h", 10.7752755672, 106.7067973757, res=8)

DGGAL ZoneID to GeoJSON

1
2
3
4
from vgrid.conversion.dggs2geo.dggal2geo import dggal2geojson

# Convert ZoneID to GeoJSON FeatureCollection
fc = dggal2geojson("isea3h", zone_id)

Conversion module for vgrid.

This module provides functions to convert between different coordinate systems, geographic data formats, and discrete global grid systems (DGGS).

a5compact(input_data, a5_hex=None, output_format='gpd')

Compact A5 cells. Flexible input/output format. input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'geoparquet' Output is always written to the current directory if file-based.

Source code in vgrid/conversion/dggscompact/a5compact.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
def a5compact(
    input_data,
    a5_hex=None,
    output_format="gpd",
):
    """
    Compact A5 cells. Flexible input/output format.
    input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs
    output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'geoparquet'
    Output is always written to the current directory if file-based.
    """
    if not a5_hex:
        a5_hex = "a5"
    gdf = process_input_data_compact(input_data, a5_hex)
    a5_hexes = gdf[a5_hex].drop_duplicates().tolist()
    if not a5_hexes:
        print(f"No A5 IDs found in <{a5_hex}> field.")
        return
    try:
        a5_hexes_compact = a5_compact(a5_hexes)
    except Exception:
        raise Exception("Compact cells failed. Please check your A5 ID field.")
    if not a5_hexes_compact:
        return None
    rows = []
    for a5_hex_compact in a5_hexes_compact:
        try:
            cell_polygon = a52geo(a5_hex_compact)
            cell_resolution = a5.get_resolution(a5.hex_to_bigint(a5_hex_compact))
            num_edges = 5  # A5 cells are pentagons
            row = geodesic_dggs_to_geoseries(
                "a5", a5_hex_compact, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue
    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs="EPSG:4326")
    ouput_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            ouput_name = f"{base}_a5_compacted"
        else:
            ouput_name = f"a5_compacted"
    return convert_to_output_format(out_gdf, output_format, ouput_name)

a5expand(input_data, resolution, a5_hex=None, output_format='gpd')

Expand (uncompact) A5 cells to a target resolution. Flexible input/output format. input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs resolution: target A5 resolution (int) output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'parquet', 'geoparquet' Output is always written to the current directory if file-based.

Source code in vgrid/conversion/dggscompact/a5compact.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
def a5expand(
    input_data,
    resolution,
    a5_hex=None,
    output_format="gpd", 
):
    """
    Expand (uncompact) A5 cells to a target resolution. Flexible input/output format.
    input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs
    resolution: target A5 resolution (int)
    output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'parquet', 'geoparquet'
    Output is always written to the current directory if file-based.
    """
    if a5_hex is None:
        a5_hex = "a5"
    resolution = validate_a5_resolution(resolution)
    gdf = process_input_data_compact(input_data, a5_hex)
    a5_hexes = gdf[a5_hex].drop_duplicates().tolist()
    if not a5_hexes:
        print(f"No A5 Hexes found in <{a5_hex}> field.")
        return
    try:
        max_res = max(a5.get_resolution(a5.hex_to_bigint(a5_hex)) for a5_hex in a5_hexes)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None
        a5_hexes_expand = a5_expand(a5_hexes, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your A5 ID field and resolution.")
    if not a5_hexes_expand:
        return None
    rows = []
    for a5_hex_expand in a5_hexes_expand:
        try:
            cell_polygon = a52geo(a5_hex_expand)
            cell_resolution = resolution
            num_edges = 5  # A5 cells are pentagons
            row = geodesic_dggs_to_geoseries(
                "a5", a5_hex_expand, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue
    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs="EPSG:4326")
    ouput_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            ouput_name = f"{base}_a5_expanded"
        else:
            ouput_name = f"a5_expanded"
    return convert_to_output_format(out_gdf, output_format, ouput_name)

easecompact(input_data, ease_id=None, output_format='gpd')

Compact EASE cells from input data.

Source code in vgrid/conversion/dggscompact/easecompact.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def easecompact(
    input_data,
    ease_id=None,
    output_format="gpd",    
):
    """Compact EASE cells from input data."""
    if not ease_id:
        ease_id = "ease"

    gdf = process_input_data_compact(input_data, ease_id)
    ease_ids = gdf[ease_id].drop_duplicates().tolist()

    if not ease_ids:
        print(f"No EASE IDs found in <{ease_id}> field.")
        return

    try:
        ease_ids_compact = ease_compact(ease_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your EASE ID field.")

    if not ease_ids_compact:
        return None

    rows = []
    for ease_id_compact in ease_ids_compact:
        try:
            cell_polygon = ease2geo(ease_id_compact)
            cell_resolution = get_ease_resolution(ease_id_compact)
            num_edges = 4  # EASE cells are rectangular
            row = geodesic_dggs_to_geoseries(
                "ease", ease_id_compact, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_ease_compacted"
        else:
            output_name = f"ease_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

easeexpand(input_data, resolution, ease_id=None, output_format='gpd')

Expand EASE cells to a target resolution.

Source code in vgrid/conversion/dggscompact/easecompact.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
def easeexpand(
    input_data,
    resolution,
    ease_id=None,
    output_format="gpd", 
):
    """Expand EASE cells to a target resolution."""
    if ease_id is None:
        ease_id = "ease"

    gdf = process_input_data_compact(input_data, ease_id)
    ease_ids = gdf[ease_id].drop_duplicates().tolist()

    if not ease_ids:
        print(f"No EASE IDs found in <{ease_id}> field.")
        return

    try:
        max_res = max(int(ease_id[1]) for ease_id in ease_ids)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None

        ease_ids_expand = ease_expand(ease_ids, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your EASE ID field and resolution.")

    if not ease_ids_expand:
        return None

    rows = []
    for ease_id_expand in ease_ids_expand:
        try:
            cell_polygon = ease2geo(ease_id_expand)
            cell_resolution = resolution
            num_edges = 4  # EASE cells are rectangular
            row = geodesic_dggs_to_geoseries(
                "ease", ease_id_expand, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_ease_expanded"
        else:
            output_name = f"ease_expanded"

    return convert_to_output_format(out_gdf, output_format, output_name)

geohashcompact(input_data, geohash_id=None, output_format='gpd')

Compact Geohash cells from input data.

Source code in vgrid/conversion/dggscompact/geohashcompact.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def geohashcompact(
    input_data,
    geohash_id=None,
    output_format="gpd", 
):
    """Compact Geohash cells from input data."""
    if not geohash_id:
        geohash_id = "geohash"

    gdf = process_input_data_compact(input_data, geohash_id)
    geohash_ids = gdf[geohash_id].drop_duplicates().tolist()

    if not geohash_ids:
        print(f"No Geohash IDs found in <{geohash_id}> field.")
        return

    try:
        geohash_ids_compact = geohash_compact(geohash_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your Geohash ID field.")

    if not geohash_ids_compact:
        return None

    rows = []
    for geohash_id_compact in geohash_ids_compact:
        try:
            cell_polygon = geohash2geo(geohash_id_compact)
            cell_resolution = get_geohash_resolution(geohash_id_compact)
            row = graticule_dggs_to_geoseries(
                "geohash", geohash_id_compact, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_geohash_compacted"
        else:
            output_name = f"geohash_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

geohashexpand(input_data, resolution, geohash_id=None, output_format='gpd')

Expand Geohash cells to a target resolution.

Source code in vgrid/conversion/dggscompact/geohashcompact.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def geohashexpand(
    input_data,
    resolution,
    geohash_id=None,
    output_format="gpd", 
):
    """Expand Geohash cells to a target resolution."""
    if geohash_id is None:
        geohash_id = "geohash"

    gdf = process_input_data_compact(input_data, geohash_id)
    geohash_ids = gdf[geohash_id].drop_duplicates().tolist()

    if not geohash_ids:
        print(f"No Geohash IDs found in <{geohash_id}> field.")
        return

    try:
        max_res = max(len(geohash_id) for geohash_id in geohash_ids)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None

        geohash_ids_expand = geohash_expand(geohash_ids, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your Geohash ID field and resolution.")

    if not geohash_ids_expand:
        return None

    rows = []
    for geohash_id_expand in geohash_ids_expand:
        try:
            cell_polygon = geohash2geo(geohash_id_expand)
            cell_resolution = resolution
            row = graticule_dggs_to_geoseries(
                "geohash", geohash_id_expand, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_geohash_expanded"
        else:
            output_name = f"geohash_expanded"

    return convert_to_output_format(out_gdf, output_format, output_name)

h3compact(input_data, h3_id=None, output_format='gpd')

Compact H3 cells. Flexible input/output format. input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'geoparquet' Output is always written to the current directory if file-based.

Source code in vgrid/conversion/dggscompact/h3compact.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def h3compact(
    input_data,
    h3_id=None,
    output_format="gpd", 
):
    """
    Compact H3 cells. Flexible input/output format.
    input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs
    output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'geoparquet'
    Output is always written to the current directory if file-based.
    """
    if h3_id is None:
        h3_id = "h3"
    gdf = process_input_data_compact(input_data, h3_id)
    h3_ids = gdf[h3_id].drop_duplicates().tolist()
    if not h3_ids:
        print(f"No H3 IDs found in <{h3_id}> field.")
        return
    try:
        h3_ids_compact = h3.compact_cells(h3_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your H3 ID field.")
    if not h3_ids_compact:
        return None
    # Build output GeoDataFrame
    rows = []
    for h3_id_compact in h3_ids_compact:        
        try:
            cell_polygon = h32geo(h3_id_compact)
            cell_resolution = h3.get_resolution(h3_id_compact)
            num_edges = 6
            if h3.is_pentagon(h3_id_compact):
                num_edges = 5
            row = geodesic_dggs_to_geoseries(
                "h3", h3_id_compact, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue
    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    # If output_format is file-based, set ouput_name as just the filename in current directory
    ouput_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            ouput_name = f"{base}_h3_compacted"
        else:
            ouput_name = f"h3_compacted"

    return convert_to_output_format(out_gdf, output_format, ouput_name)

h3expand(input_data, resolution, h3_id=None, output_format='gpd')

Expand (uncompact) H3 cells to a target resolution. Flexible input/output format. input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs resolution: target H3 resolution (int) output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'parquet', 'geoparquet' Output is always written to the current directory if file-based.

Source code in vgrid/conversion/dggscompact/h3compact.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def h3expand(
    input_data,
    resolution,
    h3_id=None,
    output_format="gpd", 
):
    """
    Expand (uncompact) H3 cells to a target resolution. Flexible input/output format.
    input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs
    resolution: target H3 resolution (int)
    output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'parquet', 'geoparquet'
    Output is always written to the current directory if file-based.
    """
    if h3_id is None:
        h3_id = "h3"
    resolution = validate_h3_resolution(resolution)
    gdf = process_input_data_compact(input_data, h3_id)
    h3_ids = gdf[h3_id].drop_duplicates().tolist()
    if not h3_ids:
        print(f"No H3 IDs found in <{h3_id}> field.")
        return
    try:
        max_res = max(h3.get_resolution(hid) for hid in h3_ids)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None
        h3_ids_expand = h3.uncompact_cells(h3_ids, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your H3 ID field and resolution.")
    if not h3_ids_expand:
        return None
    # Build output GeoDataFrame
    rows = []
    for h3_id_expand in h3_ids_expand:
        try:
            cell_polygon = h32geo(h3_id_expand)
            cell_resolution = h3.get_resolution(h3_id_expand)
            num_edges = 6
            if h3.is_pentagon(h3_id_expand):
                num_edges = 5
            row = geodesic_dggs_to_geoseries(
                "h3", h3_id_expand, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue
    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    # If output_format is file-based, set ouput_name as just the filename in current directory
    ouput_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            ouput_name = f"{base}_h3_expanded"
        else:
            ouput_name = f"h3_expanded"

    return convert_to_output_format(out_gdf, output_format, ouput_name)

isea3hcompact(input_data, isea3h_id=None, output_format='gpd')

Compact ISEA3H cells from input data.

Source code in vgrid/conversion/dggscompact/isea3hcompact.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
def isea3hcompact(
    input_data,
    isea3h_id=None,
    output_format="gpd", 
):
    """Compact ISEA3H cells from input data."""
    if not isea3h_id:
        isea3h_id = "isea3h"

    gdf = process_input_data_compact(input_data, isea3h_id)
    isea3h_ids = gdf[isea3h_id].drop_duplicates().tolist()

    if not isea3h_ids:
        print(f"No ISEA3H IDs found in <{isea3h_id}> field.")
        return

    try:
        isea3h_ids_compact = isea3h_compact(isea3h_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your ISEA3H ID field.")

    if not isea3h_ids_compact:
        return None

    rows = []
    for isea3h_id_compact in isea3h_ids_compact:
        try:
            cell_polygon = isea3h2geo(isea3h_id_compact)
            cell_resolution = get_isea3h_resolution(isea3h_id_compact)
            num_edges = 6  # ISEA3H cells are hexagonal
            row = geodesic_dggs_to_geoseries(
                "isea3h", isea3h_id_compact, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    file_formats = ["csv", "geojson", "shapefile", "gpkg", "parquet", "geoparquet"]
    output_name = None
    if output_format in file_formats:
        ext_map = {
            "csv": ".csv",
            "geojson": ".geojson",
            "shapefile": ".shp",
            "gpkg": ".gpkg",
            "parquet": ".parquet",
            "geoparquet": ".parquet",
        }
        ext = ext_map.get(output_format, "")
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_isea3h_compacted{ext}"
        else:
            output_name = f"isea3h_compacted{ext}"

    return convert_to_output_format(out_gdf, output_format, output_name)

isea3hexpand(input_data, resolution, isea3h_id=None, output_format='gpd')

Expand ISEA3H cells to a target resolution.

Source code in vgrid/conversion/dggscompact/isea3hcompact.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
def isea3hexpand(
    input_data,
    resolution,
    isea3h_id=None,
    output_format="gpd", 
):
    """Expand ISEA3H cells to a target resolution."""
    if isea3h_id is None:
        isea3h_id = "isea3h"

    gdf = process_input_data_compact(input_data, isea3h_id)
    isea3h_ids = gdf[isea3h_id].drop_duplicates().tolist()

    if not isea3h_ids:
        print(f"No ISEA3H IDs found in <{isea3h_id}> field.")
        return

    try:
        max_res = max(get_isea3h_resolution(isea3h_id) for isea3h_id in isea3h_ids)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None

        isea3h_cells_expand = isea3h_expand(isea3h_ids, resolution)
        isea3h_ids_expand = [cell.get_cell_id() for cell in isea3h_cells_expand]
    except Exception:
        raise Exception("Expand cells failed. Please check your ISEA3H ID field and resolution.")

    if not isea3h_ids_expand:
        return None

    rows = []
    for isea3h_id_expand in isea3h_ids_expand:
        try:
            cell_polygon = isea3h2geo(isea3h_id_expand)
            cell_resolution = resolution
            num_edges = 6  # ISEA3H cells are hexagonal
            row = geodesic_dggs_to_geoseries(
                "isea3h", isea3h_id_expand, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    file_formats = ["csv", "geojson", "shapefile", "gpkg", "parquet", "geoparquet"]
    output_name = None
    if output_format in file_formats:
        ext_map = {
            "csv": ".csv",
            "geojson": ".geojson",
            "shapefile": ".shp",
            "gpkg": ".gpkg",
            "parquet": ".parquet",
            "geoparquet": ".parquet",
        }
        ext = ext_map.get(output_format, "")
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_isea3h_expanded{ext}"
        else:
            output_name = f"isea3h_expanded{ext}"

    return convert_to_output_format(out_gdf, output_format, output_name)

olccompact(input_data, olc_id=None, output_format='gpd')

Compact OLC cells from input data.

Source code in vgrid/conversion/dggscompact/olccompact.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def olccompact(
    input_data,
    olc_id=None,
    output_format="gpd", 
):
    """Compact OLC cells from input data."""
    if not olc_id:
        olc_id = "olc"

    gdf = process_input_data_compact(input_data, olc_id)
    olc_ids = gdf[olc_id].drop_duplicates().tolist()

    if not olc_ids:
        print(f"No OLC IDs found in <{olc_id}> field.")
        return

    try:
        olc_ids_compact = olc_compact(olc_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your OLC ID field.")

    if not olc_ids_compact:
        return None

    rows = []
    for olc_id_compact in olc_ids_compact:
        try:
            cell_polygon = olc2geo(olc_id_compact)
            cell_resolution = get_olc_resolution(olc_id_compact)
            row = graticule_dggs_to_geoseries(
                "olc", olc_id_compact, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_olc_compacted"
        else:
            output_name = f"olc_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

qtmcompact(input_data, qtm_id='qtm', output_format='gpd')

Compact QTM cells from input data.

Source code in vgrid/conversion/dggscompact/qtmcompact.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def qtmcompact(
    input_data,
    qtm_id="qtm",
    output_format="gpd",
):
    """Compact QTM cells from input data."""

    gdf = process_input_data_compact(input_data, qtm_id)
    qtm_ids = gdf[qtm_id].drop_duplicates().tolist()

    if not qtm_ids:
        print(f"No QTM IDs found in <{qtm_id}> field.")
        return

    try:
        qtm_ids_compact = qtm_compact(qtm_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your QTM ID field.")

    if not qtm_ids_compact:
        return None

    rows = []
    for qtm_id_compact in qtm_ids_compact:
        try:
            cell_polygon = qtm2geo(qtm_id_compact)
            cell_resolution = get_qtm_resolution(qtm_id_compact)
            num_edges = 3  # QTM cells are triangular
            row = geodesic_dggs_to_geoseries(
                "qtm", qtm_id_compact, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_qtm_compacted"
        else:
            output_name = f"qtm_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

qtmexpand(input_data, resolution, qtm_id='qtm', output_format='gpd')

Expand QTM cells to a target resolution.

Source code in vgrid/conversion/dggscompact/qtmcompact.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def qtmexpand(
    input_data,
    resolution,
    qtm_id="qtm",
    output_format="gpd",
):
    """Expand QTM cells to a target resolution."""
    if qtm_id is None:
        qtm_id = "qtm"

    gdf = process_input_data_compact(input_data, qtm_id)
    qtm_ids = gdf[qtm_id].drop_duplicates().tolist()

    if not qtm_ids:
        print(f"No QTM IDs found in <{qtm_id}> field.")
        return

    try:
        max_res = max(len(qtm_id) for qtm_id in qtm_ids)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None

        qtm_ids_expand = qtm_expand(qtm_ids, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your QTM ID field and resolution.")

    if not qtm_ids_expand:
        return None

    rows = []
    for qtm_id_expand in qtm_ids_expand:
        try:
            cell_polygon = qtm2geo(qtm_id_expand)
            cell_resolution = resolution
            num_edges = 3  # QTM cells are triangular
            row = geodesic_dggs_to_geoseries(
                "qtm", qtm_id_expand, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_qtm_expanded"
        else:
            output_name = f"qtm_expanded"

    return convert_to_output_format(out_gdf, output_format, output_name)

quadkeycompact(input_data, quadkey_id='quadkey', output_format='gpd')

Compact Quadkey cells from input data.

Source code in vgrid/conversion/dggscompact/quadkeycompact.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
def quadkeycompact(
    input_data,
    quadkey_id="quadkey",
    output_format="gpd",
):
    """Compact Quadkey cells from input data."""

    gdf = process_input_data_compact(input_data, quadkey_id)
    quadkey_ids = gdf[quadkey_id].drop_duplicates().tolist()

    if not quadkey_ids:
        print(f"No Quadkey IDs found in <{quadkey_id}> field.")
        return

    try:
        quadkey_ids_compact = quadkey_compact(quadkey_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your Quadkey ID field.")

    if not quadkey_ids_compact:
        return None

    rows = []
    for quadkey_id_compact in quadkey_ids_compact:
        try:
            cell_polygon = quadkey2geo(quadkey_id_compact)
            cell_resolution = quadkey_resolution(quadkey_id_compact)
            row = graticule_dggs_to_geoseries(
                "quadkey", quadkey_id_compact, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_quadkey_compacted"
        else:
            output_name = f"quadkey_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

quadkeyexpand(input_data, resolution, quadkey_id='quadkey', output_format='gpd')

Expand Quadkey cells to a target resolution.

Source code in vgrid/conversion/dggscompact/quadkeycompact.py
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def quadkeyexpand(
    input_data,
    resolution,
    quadkey_id="quadkey",
    output_format="gpd",
):
    """Expand Quadkey cells to a target resolution."""

    gdf = process_input_data_compact(input_data, quadkey_id)
    quadkey_ids = gdf[quadkey_id].drop_duplicates().tolist()

    if not quadkey_ids:
        print(f"No Quadkey IDs found in <{quadkey_id}> field.")
        return

    try:
        max_res = max(len(quadkey_id) for quadkey_id in quadkey_ids)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None

        quadkey_ids_expand = quadkey_expand(quadkey_ids, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your Quadkey ID field and resolution.")

    if not quadkey_ids_expand:
        return None

    rows = []
    for quadkey_id_expand in quadkey_ids_expand:
        try:
            cell_polygon = quadkey2geo(quadkey_id_expand)
            cell_resolution = resolution
            row = graticule_dggs_to_geoseries(
                "quadkey", quadkey_id_expand, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_quadkey_expanded"
        else:
            output_name = f"quadkey_expanded"

    return convert_to_output_format(out_gdf, output_format, output_name)

raster2dggal(raster_path, dggs_type, resolution=None, output_format='gpd')

Convert raster data to DGGAL grid cells for a given type and resolution.

  • raster_path: path to raster in geographic CRS (EPSG:4326)
  • dggs_type: one of DGGAL_TYPES
  • resolution: integer resolution understood by the dgg CLI for the chosen type. If None, auto-selected
  • output_format: see OUTPUT_FORMATS
Source code in vgrid/conversion/raster2dggs/raster2dggal.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def raster2dggal(raster_path, dggs_type: str, resolution: int | None = None, output_format: str = "gpd"):
    """
    Convert raster data to DGGAL grid cells for a given type and resolution.

    - raster_path: path to raster in geographic CRS (EPSG:4326)
    - dggs_type: one of DGGAL_TYPES
    - resolution: integer resolution understood by the `dgg` CLI for the chosen type. If None, auto-selected
    - output_format: see OUTPUT_FORMATS
    """
    if dggs_type not in DGGAL_TYPES:
        raise ValueError(f"dggs_type must be one of {DGGAL_TYPES}")
    # Open the raster file to get metadata and data
    with rasterio.open(raster_path) as src:
        raster_data = src.read()  # Read all bands
        transform = src.transform
        width, height = src.width, src.height
        band_count = src.count  # Number of bands in the raster

    # Auto-select resolution if not provided
    if resolution is None:
        resolution = get_nearest_dggal_resolution(raster_path, dggs_type)
        print(f"Nearest {dggs_type} resolution determined: {resolution}")
    else:
        resolution = validate_dggal_resolution(dggs_type, resolution)

    # Collect unique ZoneIDs by scanning raster pixels (like raster2h3)
    zone_ids = set()
    for row in range(height):
        for col in range(width):
            lon, lat = transform * (col, row)
            try:
                zid = latlon2dggal(dggs_type, lat, lon, resolution)
                if zid:
                    zone_ids.add(zid)
            except Exception:
                continue
    print(zone_ids)

raster2h3(raster_path, resolution=None, output_format='gpd')

Convert raster data to H3 DGGS format.

Parameters:

Name Type Description Default
raster_path str

Path to the raster file

required
resolution int

H3 resolution [0..15]. If None, automatically determined

None
output_format str

Output format. Options: - None: Returns GeoPandas GeoDataFrame (default) - "gpd": Returns GeoPandas GeoDataFrame - "csv": Returns CSV file path - "geojson": Returns GeoJSON file path - "geojson_dict": Returns GeoJSON FeatureCollection as Python dict - "parquet": Returns Parquet file path - "shapefile"/"shp": Returns Shapefile file path - "gpkg"/"geopackage": Returns GeoPackage file path

'gpd'
Source code in vgrid/conversion/raster2dggs/raster2h3.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def raster2h3(raster_path, resolution=None, output_format="gpd"):
    """
    Convert raster data to H3 DGGS format.

    Args:
        raster_path (str): Path to the raster file
        resolution (int, optional): H3 resolution [0..15]. If None, automatically determined
        output_format (str, optional): Output format. Options:
            - None: Returns GeoPandas GeoDataFrame (default)
            - "gpd": Returns GeoPandas GeoDataFrame
            - "csv": Returns CSV file path
            - "geojson": Returns GeoJSON file path
            - "geojson_dict": Returns GeoJSON FeatureCollection as Python dict
            - "parquet": Returns Parquet file path
            - "shapefile"/"shp": Returns Shapefile file path
            - "gpkg"/"geopackage": Returns GeoPackage file path
    Returns:
        Various formats based on output_format parameter
    Raises:
        ValueError: If resolution is not in valid range [0..15]
        ImportError: If required dependencies are not available for specific formats
    """
    # Step 1: Determine the nearest H3 resolution if none is provided
    if resolution is None:
        resolution = get_nearest_h3_resolution(raster_path)
        print(f"Nearest H3 resolution determined: {resolution}")
    else:
        resolution = validate_geohash_resolution(resolution)

    # Open the raster file to get metadata and data
    with rasterio.open(raster_path) as src:
        raster_data = src.read()  # Read all bands
        transform = src.transform
        width, height = src.width, src.height
        band_count = src.count  # Number of bands in the raster

    h3_ids = set()
    for row in range(height):
        for col in range(width):
            lon, lat = transform * (col, row)
            h3_id = h3.latlng_to_cell(lat, lon, resolution)
            h3_ids.add(h3_id)

    # Build GeoDataFrame as the base
    properties = []
    for h3_id in tqdm(h3_ids, desc="Converting raster to H3", unit=" cells"):
        centroid_lat, centroid_lon = h3.cell_to_latlng(h3_id)
        col, row = ~transform * (centroid_lon, centroid_lat)
        if 0 <= col < width and 0 <= row < height:
            values = raster_data[:, int(row), int(col)]
            cell_polygon = h32geo(h3_id)
            num_edges = 6
            if h3.is_pentagon(h3_id):
                num_edges = 5
            base_props = geodesic_dggs_to_geoseries(
                "h3", h3_id, resolution, cell_polygon, num_edges
            )
            band_properties = {f"band_{i + 1}": values[i] for i in range(band_count)}
            base_props.update(convert_numpy_types(band_properties))
            properties.append(base_props)
    # Build GeoDataFrame
    gdf = gpd.GeoDataFrame(properties, geometry="geometry", crs="EPSG:4326")

    # Use centralized output utility
    base_name = os.path.splitext(os.path.basename(raster_path))[0]
    output_name = f"{base_name}2h3" if output_format is not None else None
    return convert_to_output_format(gdf, output_format, output_name)

raster2qtm(raster_path, resolution=None, output_format='gpd')

Convert raster data to QTM DGGS output_format.

Parameters:

Name Type Description Default
raster_path str

Path to the raster file

required
resolution int

QTM resolution level. If None, will be determined automatically.

None
output_format str

Output output_format, see supported formats

'gpd'

Returns:

Type Description

Various formats based on output_format parameter

Source code in vgrid/conversion/raster2dggs/raster2qtm.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
def raster2qtm(raster_path, resolution=None, output_format="gpd"):
    """
    Convert raster data to QTM DGGS output_format.

    Args:
        raster_path (str): Path to the raster file
        resolution (int, optional): QTM resolution level. If None, will be determined automatically.
        output_format (str): Output output_format, see supported formats

    Returns:
        Various formats based on output_format parameter
    """
    # Step 1: Determine the nearest qtm resolution if none is provided
    if resolution is None:
        resolution = get_nearest_qtm_resolution(raster_path)
        print(f"Nearest qtm resolution determined: {resolution}")
    else:
        resolution = validate_qtm_resolution(resolution)    
    # Open the raster file to get metadata and data
    with rasterio.open(raster_path) as src:
        raster_data = src.read()  # Read all bands
        transform = src.transform
        width, height = src.width, src.height
        band_count = src.count  # Number of bands in the raster

    qtm_ids = set()

    for row in range(height):
        for col in range(width):
            lon, lat = transform * (col, row)
            qtm_id = latlon2qtm(lat, lon, resolution)
            qtm_ids.add(qtm_id)

    # Sample the raster values at the centroids of the qtm cells
    qtm_data = []

    for qtm_id in tqdm(qtm_ids, desc="Resampling", unit=" cells"):
        # Get the centroid of the qtm cell
        cell_polygon = qtm2geo(qtm_id)
        centroid = cell_polygon.centroid
        centroid_lon, centroid_lat = centroid.x, centroid.y

        # Sample the raster values at the centroid (lat, lon)
        col, row = ~transform * (centroid_lon, centroid_lat)

        if 0 <= col < width and 0 <= row < height:
            # Get the values for all bands at this centroid
            values = raster_data[:, int(row), int(col)]
            qtm_data.append(
                {
                    "qtm": qtm_id,
                    **{f"band_{i + 1}": values[i] for i in range(band_count)},
                }
            )

    # Always convert to GeoDataFrame for output
    # Build GeoDataFrame
    geometries = []
    properties = []
    for data in tqdm(qtm_data, desc="Converting raster to QTM", unit=" cells"):
        qtm_id = data["qtm"]
        cell_polygon = qtm2geo(qtm_id)
        geometries.append(cell_polygon)
        props = {"qtm": qtm_id}
        props.update({f"band_{i + 1}": data[f"band_{i + 1}"] for i in range(band_count)})
        properties.append(convert_numpy_types(props))
    gdf = gpd.GeoDataFrame(properties, geometry=geometries, crs="EPSG:4326")

    # Use centralized output utility
    base_name = os.path.splitext(os.path.basename(raster_path))[0]
    output_name = f"{base_name}2qtm" if output_format is not None else None
    return convert_to_output_format(gdf, output_format, output_name)

raster2quadkey(raster_path, resolution=None, output_format='gpd')

Convert raster to quadkey output_format

Parameters:

Name Type Description Default
raster_path str

Path to input raster file

required
resolution int

Quadkey resolution level [0-29]. If None, will be determined automatically

None
output_format str

Output output_format, see supported formats

'gpd'

Returns:

Type Description

Various formats based on output_format parameter

Source code in vgrid/conversion/raster2dggs/raster2quadkey.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
def raster2quadkey(raster_path, resolution=None, output_format="gpd"):
    """Convert raster to quadkey output_format

    Args:
        raster_path (str): Path to input raster file
        resolution (int, optional): Quadkey resolution level [0-29]. If None, will be determined automatically
        output_format (str, optional): Output output_format, see supported formats

    Returns:
        Various formats based on output_format parameter
    """
    # Step 1: Determine the nearest quadkey resolution if none is provided
    if resolution is None:
        resolution = get_nearest_quadkey_resolution(raster_path)
        print(f"Nearest quadkey resolution determined: {resolution}")
    else:
        resolution = validate_quadkey_resolution(resolution)
    # Open the raster file to get metadata and data
    with rasterio.open(raster_path) as src:
        raster_data = src.read()  # Read all bands
        transform = src.transform
        width, height = src.width, src.height
        band_count = src.count  # Number of bands in the raster

    quadkey_ids = set()

    for row in range(height):
        for col in range(width):
            lon, lat = transform * (col, row)
            quadkey_id = tilecode.latlon2quadkey(lat, lon, resolution)
            quadkey_ids.add(quadkey_id)

    # Sample the raster values at the centroids of the quadkey cells
    quadkey_data = []

    for quadkey_id in tqdm(quadkey_ids, desc="Resampling", unit=" cells"):
        # Get the centroid of the quadkey cell
        centroid_lat, centroid_lon = tilecode.quadkey2latlon(quadkey_id)

        # Sample the raster values at the centroid (lat, lon)
        col, row = ~transform * (centroid_lon, centroid_lat)

        if 0 <= col < width and 0 <= row < height:
            # Get the values for all bands at this centroid
            values = raster_data[:, int(row), int(col)]
            quadkey_data.append(
                {
                    "quadkey": quadkey_id,
                    **{
                        f"band_{i + 1}": values[i] for i in range(band_count)
                    },
                }
            )

    # Always convert to GeoDataFrame for output
    # Build GeoDataFrame
    geometries = []
    properties = []
    for data in tqdm(quadkey_data, desc="Converting raster to Quadkey", unit=" cells"):
        quadkey_id = data["quadkey"]
        tile = mercantile.quadkey_to_tile(quadkey_id)
        z = tile.z
        x = tile.x
        y = tile.y
        bounds = mercantile.bounds(x, y, z)
        min_lat, min_lon = bounds.south, bounds.west
        max_lat, max_lon = bounds.north, bounds.east
        cell_polygon = Polygon([
            [min_lon, min_lat],
            [max_lon, min_lat],
            [max_lon, max_lat],
            [min_lon, max_lat],
            [min_lon, min_lat],
        ])
        geometries.append(cell_polygon)
        props = {"quadkey": quadkey_id}
        props.update({f"band_{i + 1}": data[f"band_{i + 1}"] for i in range(band_count)})
        properties.append(convert_numpy_types(props))
    gdf = gpd.GeoDataFrame(properties, geometry=geometries, crs="EPSG:4326")

    # Use centralized output utility
    base_name = os.path.splitext(os.path.basename(raster_path))[0]
    output_name = f"{base_name}2quadkey" if output_format is not None else None
    return convert_to_output_format(gdf, output_format, output_name)

raster2rhealpix(raster_path, resolution=None, output_format='gpd')

Convert raster data to rHEALPix DGGS.

Source code in vgrid/conversion/raster2dggs/raster2rhealpix.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
def raster2rhealpix(raster_path, resolution=None, output_format="gpd"):
    """
    Convert raster data to rHEALPix DGGS.
    """
    # Step 1: Determine the nearest rhealpix resolution if none is provided
    if resolution is None:
        resolution = get_nearest_rhealpix_resolution(raster_path)
        print(f"Nearest rhealpix resolution determined: {resolution}")
    else:
        resolution = validate_rhealpix_resolution(resolution)   
    # Open the raster file to get metadata and data
    with rasterio.open(raster_path) as src:
        raster_data = src.read()  # Read all bands
        transform = src.transform
        width, height = src.width, src.height
        band_count = src.count  # Number of bands in the raster

    rhealpix_ids = set()
    for row in range(height):
        for col in range(width):
            lon, lat = transform * (col, row)
            point = (lon, lat)
            rhealpix_cell = rhealpix_dggs.cell_from_point(
                resolution, point, plane=False
            )
            rhealpix_ids.add(str(rhealpix_cell))

    # Build GeoDataFrame as the base
    properties = []
    for rhealpix_id in tqdm(rhealpix_ids, desc="Converting raster to rHEALPix", unit=" cells"):
        rhealpix_uids = (rhealpix_id[0],) + tuple(map(int, rhealpix_id[1:]))
        rhealpix_cell = rhealpix_dggs.cell(rhealpix_uids)
        cell_polygon = rhealpix_cell_to_polygon(rhealpix_cell)
        num_edges = 4
        if rhealpix_cell.ellipsoidal_shape() == "dart":
            num_edges = 3
        centroid_lat, centroid_lon, avg_edge_len, cell_area, cell_perimeter = geodesic_dggs_metrics(
            cell_polygon, num_edges
        )
        col, row = ~transform * (centroid_lon, centroid_lat)
        if 0 <= col < width and 0 <= row < height:
            values = raster_data[:, int(row), int(col)]
            base_props = {
                "rhealpix": rhealpix_id,
                "resolution": resolution,
                "center_lat": centroid_lat,
                "center_lon": centroid_lon,
                "avg_edge_len": avg_edge_len,
                "cell_area": cell_area,
                "cell_perimeter": cell_perimeter,
                "geometry": cell_polygon,
            }
            band_properties = {f"band_{i + 1}": values[i] for i in range(band_count)}
            base_props.update(convert_numpy_types(band_properties))
            properties.append(base_props)
    # Build GeoDataFrame
    gdf = gpd.GeoDataFrame(properties, geometry="geometry", crs="EPSG:4326")

    # Use centralized output utility
    base_name = os.path.splitext(os.path.basename(raster_path))[0]
    output_name = f"{base_name}2rhealpix" if output_format is not None else None
    return convert_to_output_format(gdf, output_format, output_name)

raster2tilecode(raster_path, resolution=None, output_format='gpd')

Convert raster to tilecode output_format

Parameters:

Name Type Description Default
raster_path str

Path to input raster file

required
resolution int

Tilecode resolution level [0-26]. If None, will be determined automatically

None
output_format str

Output output_format, see supported formats

'gpd'

Returns:

Type Description

Various formats based on output_format parameter

Source code in vgrid/conversion/raster2dggs/raster2tilecode.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def raster2tilecode(raster_path, resolution=None, output_format="gpd"):
    """Convert raster to tilecode output_format

    Args:
        raster_path (str): Path to input raster file
        resolution (int, optional): Tilecode resolution level [0-26]. If None, will be determined automatically
        output_format (str, optional): Output output_format, see supported formats

    Returns:
        Various formats based on output_format parameter
    """
    # Step 1: Determine the nearest tilecode resolution if none is provided
    if resolution is None:
        resolution = get_nearest_tilecode_resolution(raster_path)
        print(f"Nearest tilecode resolution determined: {resolution}")
    else:
        resolution = validate_tilecode_resolution(resolution)
    # Open the raster file to get metadata and data
    with rasterio.open(raster_path) as src:
        raster_data = src.read()  # Read all bands
        transform = src.transform
        width, height = src.width, src.height
        band_count = src.count  # Number of bands in the raster

    tilecode_ids = set()

    for row in range(height):
        for col in range(width):
            lon, lat = transform * (col, row)
            tilecode_id = tilecode.latlon2tilecode(lat, lon, resolution)
            tilecode_ids.add(tilecode_id)

    # Sample the raster values at the centroids of the tilecode cells
    tilecode_data = []

    for tilecode_id in tqdm(tilecode_ids, desc="Resampling", unit=" cells"):
        # Get the centroid of the tilecode cell
        centroid_lat, centroid_lon = tilecode.tilecode2latlon(tilecode_id)

        # Sample the raster values at the centroid (lat, lon)
        col, row = ~transform * (centroid_lon, centroid_lat)

        if 0 <= col < width and 0 <= row < height:
            # Get the values for all bands at this centroid
            values = raster_data[:, int(row), int(col)]
            tilecode_data.append(
                {
                    "tilecode": tilecode_id,
                    **{
                        f"band_{i + 1}": values[i] for i in range(band_count)
                    },
                }
            )

    # Always convert to GeoDataFrame for output
    # Build GeoDataFrame
    geometries = []
    properties = []
    for data in tqdm(tilecode_data, desc="Converting raster to Tilecode", unit=" cells"):
        tilecode_id = data["tilecode"]
        match = re.match(r"z(\d+)x(\d+)y(\d+)", tilecode_id)
        if match:
            z = int(match.group(1))
            x = int(match.group(2))
            y = int(match.group(3))
            bounds = mercantile.bounds(x, y, z)
            if bounds:
                min_lat, min_lon = bounds.south, bounds.west
                max_lat, max_lon = bounds.north, bounds.east
                cell_polygon = Polygon([
                    [min_lon, min_lat],
                    [max_lon, min_lat],
                    [max_lon, max_lat],
                    [min_lon, max_lat],
                    [min_lon, min_lat],
                ])
                geometries.append(cell_polygon)
                props = {"tilecode": tilecode_id}
                props.update({f"band_{i + 1}": data[f"band_{i + 1}"] for i in range(band_count)})
                properties.append(convert_numpy_types(props))
    gdf = gpd.GeoDataFrame(properties, geometry=geometries, crs="EPSG:4326")

    # Use centralized output utility
    base_name = os.path.splitext(os.path.basename(raster_path))[0]
    output_name = f"{base_name}2tilecode" if output_format is not None else None
    return convert_to_output_format(gdf, output_format, output_name)

s2compact(input_data, s2_token='s2', output_format='gpd')

Compact S2 cells. Flexible input/output format. input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'geoparquet' Output is always written to the current directory if file-based.

Source code in vgrid/conversion/dggscompact/s2compact.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def s2compact(
    input_data,
    s2_token="s2",
    output_format="gpd",
):
    """
    Compact S2 cells. Flexible input/output format.
    input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs
    output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'geoparquet'
    Output is always written to the current directory if file-based.
    """
    gdf = process_input_data_compact(input_data, s2_token)
    s2_tokens = gdf[s2_token].drop_duplicates().tolist()
    if not s2_tokens:
        print(f"No S2 tokens found in <{s2_token}> field.")
        return
    try:
        s2_cells = [s2.CellId.from_token(token) for token in s2_tokens]
        s2_cells = list(set(s2_cells))
        if not s2_cells:
            print(f"No valid S2 tokens found in <{s2_token}> field.")
            return
        covering = s2.CellUnion(s2_cells)
        covering.normalize()
        s2_tokens_compact = [cell_id.to_token() for cell_id in covering.cell_ids()]
    except Exception:
        raise Exception("Compact cells failed. Please check your S2 ID field.")
    if not s2_tokens_compact:
        return None
    # Build output GeoDataFrame
    rows = []
    for s2_token_compact in s2_tokens_compact:
        try:
            cell_polygon = s22geo(s2_token_compact)
            cell_resolution = s2.CellId.from_token(s2_token_compact).level()
            num_edges = 4
            row = geodesic_dggs_to_geoseries(
                "s2", s2_token_compact, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue
    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    # If output_format is file-based, set output_name as just the filename in current directory
    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_s2_compacted"
        else:
            output_name = f"s2_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

s2expand(input_data, resolution, s2_token='s2', output_format='gpd')

Expand (uncompact) S2 cells to a target resolution. Flexible input/output format. input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs resolution: target S2 resolution (int) output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'parquet', 'geoparquet' Output is always written to the current directory if file-based.

Source code in vgrid/conversion/dggscompact/s2compact.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
def s2expand(
    input_data,
    resolution,
    s2_token="s2",
    output_format="gpd",
):
    """
    Expand (uncompact) S2 cells to a target resolution. Flexible input/output format.
    input_data: file path, URL, dict, GeoDataFrame, or list of cell IDs
    resolution: target S2 resolution (int)
    output_format: None, 'csv', 'geojson', 'shapefile', 'gpd', 'geojson_dict', 'gpkg', 'parquet', 'geoparquet'
    Output is always written to the current directory if file-based.
    """
    resolution = validate_s2_resolution(resolution)     
    gdf = process_input_data_compact(input_data, s2_token)
    s2_tokens = gdf[s2_token].drop_duplicates().tolist()
    if not s2_tokens:
        print(f"No S2 tokens found in <{s2_token}> field.")
        return
    try:
        s2_cells = [s2.CellId.from_token(token) for token in s2_tokens]
        s2_cells = list(set(s2_cells))
        if not s2_cells:
            print(f"No valid S2 tokens found in <{s2_token}> field.")
            return
        max_res = max(cell.level() for cell in s2_cells)
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None
        # Expand each cell to the target resolution
        expanded_cells = []
        for cell in s2_cells:
            if cell.level() >= resolution:
                expanded_cells.append(cell)
            else:
                expanded_cells.extend(cell.children(resolution))
        s2_tokens_expand = [cell_id.to_token() for cell_id in expanded_cells]
    except Exception:
        raise Exception("Expand cells failed. Please check your S2 ID field and resolution.")
    if not s2_tokens_expand:
        return None
    # Build output GeoDataFrame
    rows = []
    for s2_token_expand in s2_tokens_expand:
        try:
            cell_polygon = s22geo(s2_token_expand)
            cell_resolution = resolution
            num_edges = 4
            row = geodesic_dggs_to_geoseries(
                "s2", s2_token_expand, cell_resolution, cell_polygon, num_edges
            )
            rows.append(row)
        except Exception:
            continue
    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    # If output_format is file-based, set output_name as just the filename in current directory
    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_s2_expanded"
        else:
            output_name = f"s2_expanded"

    return convert_to_output_format(out_gdf, output_format, output_name)

tilecodecompact(input_data, tilecode_id='tilecode', output_format='gpd')

Compact Tilecode cells from input data.

Source code in vgrid/conversion/dggscompact/tilecodecompact.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def tilecodecompact(
    input_data,
    tilecode_id="tilecode",
    output_format="gpd",
):
    """Compact Tilecode cells from input data."""

    gdf = process_input_data_compact(input_data, tilecode_id)
    tilecode_ids = gdf[tilecode_id].drop_duplicates().tolist()

    if not tilecode_ids:
        print(f"No Tilecode IDs found in <{tilecode_id}> field.")
        return

    try:
        tilecode_ids_compact = tilecode_compact(tilecode_ids)
    except Exception:
        raise Exception("Compact cells failed. Please check your Tilecode ID field.")

    if not tilecode_ids_compact:
        return None

    rows = []
    for tilecode_id_compact in tilecode_ids_compact:
        try:
            cell_polygon = tilecode2geo(tilecode_id_compact)
            cell_resolution = tilecode_resolution(tilecode_id_compact)
            row = graticule_dggs_to_geoseries(
                "tilecode", tilecode_id_compact, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_tilecode_compacted"
        else:
            output_name = f"tilecode_compacted"

    return convert_to_output_format(out_gdf, output_format, output_name)

tilecodeexpand(input_data, resolution, tilecode_id='tilecode', output_format='gpd')

Expand Tilecode cells to a target resolution.

Source code in vgrid/conversion/dggscompact/tilecodecompact.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def tilecodeexpand(
    input_data,
    resolution,
    tilecode_id="tilecode",
    output_format="gpd",
):
    """Expand Tilecode cells to a target resolution."""

    gdf = process_input_data_compact(input_data, tilecode_id)
    tilecode_ids = gdf[tilecode_id].drop_duplicates().tolist()

    if not tilecode_ids:
        print(f"No Tilecode IDs found in <{tilecode_id}> field.")
        return

    try:
        max_res = max(
            int(re.match(r"z(\d+)x(\d+)y(\d+)", tid).group(1)) for tid in tilecode_ids
        )
        if resolution < max_res:
            print(f"Target expand resolution ({resolution}) must >= {max_res}.")
            return None

        tilecode_ids_expand = tilecode_expand(tilecode_ids, resolution)
    except Exception:
        raise Exception("Expand cells failed. Please check your Tilecode ID field and resolution.")

    if not tilecode_ids_expand:
        return None

    rows = []
    for tilecode_id_expand in tilecode_ids_expand:
        try:
            cell_polygon = tilecode2geo(tilecode_id_expand)
            cell_resolution = resolution
            row = graticule_dggs_to_geoseries(
                "tilecode", tilecode_id_expand, cell_resolution, cell_polygon
            )
            rows.append(row)
        except Exception:
            continue

    out_gdf = gpd.GeoDataFrame(rows, geometry="geometry",crs="EPSG:4326")

    output_name = None
    if output_format in OUTPUT_FORMATS:
        if isinstance(input_data, str):
            base = os.path.splitext(os.path.basename(input_data))[0]
            output_name = f"{base}_tilecode_expanded"
        else:
            output_name = f"tilecode_expanded"

    return convert_to_output_format(out_gdf, output_format, output_name)

vector2a5(data, resolution=None, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to A5 grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2a5.py
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
def vector2a5(
    data,
    resolution=None,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to A5 grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_a5_resolution(resolution)
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2a5(
        gdf, resolution, predicate, compact, topology, include_properties
    )
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            if resolution is not None:
                output_name = f"{base}2a5_{resolution}"
            else:
                output_name = f"{base}2a5_topology"
        else:
            if resolution is not None:
                output_name = f"a5_{resolution}"
            else:
                output_name = f"a5_topology"
    return convert_to_output_format(result, output_format, output_name)

vector2ease(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to EASE grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2ease.py
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
def vector2ease(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to EASE grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_ease_resolution(resolution)                           
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2ease(
        gdf, resolution, predicate, compact, topology, include_properties
    )
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = kwargs.get("output_name", None)
    if output_format in file_formats and output_name is None:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2ease_{resolution}"
        else:
            output_name = f"ease_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2geohash(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to Geohash grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2geohash.py
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
def vector2geohash(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to Geohash grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_geohash_resolution(resolution)
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2geohash(
        gdf, resolution, predicate, compact, topology, include_properties
    )

    # Apply compaction if requested
    if compact:
        result = geohashcompact(result, geohash_id="geohash", output_format="gpd")

    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2geohash_{resolution}"
        else:
            output_name = f"geohash_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2h3(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to H3 grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2h3.py
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
def vector2h3(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to H3 grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_h3_resolution(resolution)
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2h3(
        gdf, resolution, predicate, compact, topology, include_properties
    )
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2h3_{resolution}"
        else:
            output_name = f"h3_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2isea3h(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to ISEA3H grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2isea3h.py
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
def vector2isea3h(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to ISEA3H grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    # Allow running on all platforms
    resolution = validate_isea3h_resolution(resolution)
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2isea3h(
        gdf, resolution, predicate, compact, topology, include_properties
    )
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2isea3h_{resolution}"
        else:
            output_name = f"isea3h_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2mgrs(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to MGRS grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2mgrs.py
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
def vector2mgrs(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to MGRS grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_mgrs_resolution(resolution)
    if hasattr(data, "geometry") and hasattr(data, "columns"):
        result = geodataframe2mgrs(
            data, resolution, predicate, compact, topology, include_properties
        )
    elif isinstance(data, pd.DataFrame):
        result = dataframe2mgrs(
            data, resolution, predicate, compact, topology, include_properties
        )
    elif hasattr(data, "geom_type") or (
        isinstance(data, list) and len(data) > 0 and hasattr(data[0], "geom_type")
    ):
        result = geometry2mgrs(
            data, resolution, None, predicate, compact, topology, include_properties
        )
    elif isinstance(data, dict) and "type" in data:
        try:
            gdf = gpd.GeoDataFrame.from_features(data["features"])
            result = geodataframe2mgrs(
                gdf, resolution, predicate, compact, topology, include_properties
            )
        except Exception as e:
            raise ValueError(f"Failed to convert GeoJSON to GeoDataFrame: {str(e)}")
    elif isinstance(data, str):
        try:
            gdf = gpd.read_file(data, **kwargs)
            result = geodataframe2mgrs(
                gdf, resolution, predicate, compact, topology, include_properties
            )
        except Exception as e:
            raise ValueError(f"Failed to read file/URL {data}: {str(e)}")
    else:
        raise ValueError(f"Unsupported input type: {type(data)}")
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2mgrs_{resolution}"
        else:
            output_name = f"mgrs_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2olc(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to OLC grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2olc.py
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
def vector2olc(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to OLC grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_olc_resolution(resolution)
    gdf = process_input_data_vector(data)
    geometries = list(gdf.geometry)
    properties_list = [row.drop(labels=["geometry"]).to_dict() for idx, row in gdf.iterrows()]
    result = geometry2olc(
        geometries,
        resolution,
        properties_list,
        predicate,
        compact,
        topology,
        include_properties,
    )
    # Apply compact if requested and result is a GeoDataFrame
    if compact:
        result = olccompact(result, olc_id="olc", output_format="gpd")

    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2olc_{resolution}"
        else:
            output_name = f"olc_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2qtm(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to QTM grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2qtm.py
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
def vector2qtm(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to QTM grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_qtm_resolution(resolution)       
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2qtm(
        gdf, resolution, predicate, compact, topology, include_properties
    )

    # Apply compaction if requested
    if compact:
        result = qtmcompact(result, qtm_id="qtm", output_format="gpd")

    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2qtm_{resolution}"
        else:
            output_name = f"qtm_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2quadkey(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to Quadkey grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format. The internal processing always uses GeoDataFrame format for consistency.

Source code in vgrid/conversion/vector2dggs/vector2quadkey.py
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
def vector2quadkey(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to Quadkey grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    The internal processing always uses GeoDataFrame format for consistency.
    """
    resolution = validate_quadkey_resolution(resolution)
    gdf = process_input_data_vector(data, **kwargs)
    geometries = list(gdf.geometry)
    properties_list = [row.drop(labels=["geometry"]).to_dict() for idx, row in gdf.iterrows()]
    result = geometry2quadkey(
        geometries,
        resolution,
        properties_list,
        predicate,
        compact,
        topology,
        include_properties,
    )
    if compact:
        result = quadkeycompact(result, quadkey_id="quadkey", output_format="gpd")

    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2quadkey_{resolution}"
        else:
            output_name = f"quadkey_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2rhealpix(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to rHEALPix grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2rhealpix.py
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
def vector2rhealpix(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to rHEALPix grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_rhealpix_resolution(resolution)   
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2rhealpix(
        gdf, resolution, predicate, compact, topology, include_properties
    )
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2rhealpix_{resolution}"
        else:
            output_name = f"rhealpix_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2s2(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to S2 grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.

Source code in vgrid/conversion/vector2dggs/vector2s2.py
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
def vector2s2(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to S2 grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    """
    resolution = validate_s2_resolution(resolution) 
    gdf = process_input_data_vector(data, **kwargs)
    result = geodataframe2s2(
        gdf, resolution, predicate, compact, topology, include_properties
    )
    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2s2_{resolution}"
        else:
            output_name = f"s2_{resolution}"
    return convert_to_output_format(result, output_format, output_name)

vector2tilecode(data, resolution, predicate=None, compact=False, topology=False, output_format='gpd', include_properties=True, **kwargs)

Convert vector data to Tilecode grid cells from various input formats. If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet), the output will be saved to a file in the current directory with a default name based on the input. Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format. The internal processing always uses GeoDataFrame format for consistency.

Source code in vgrid/conversion/vector2dggs/vector2tilecode.py
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
def vector2tilecode(
    data,
    resolution,
    predicate=None,
    compact=False,
    topology=False,
    output_format="gpd",
    include_properties=True,
    **kwargs,
):
    """
    Convert vector data to Tilecode grid cells from various input formats.
    If output_format is a file-based format (csv, geojson, shapefile, gpkg, parquet, geoparquet),
    the output will be saved to a file in the current directory with a default name based on the input.
    Otherwise, returns a Python object (GeoDataFrame, dict, etc.) depending on output_format.
    The internal processing always uses GeoDataFrame format for consistency.
    """
    resolution = validate_tilecode_resolution(resolution)
    gdf = process_input_data_vector(data, **kwargs)
    geometries = list(gdf.geometry)
    properties_list = [row.drop(labels=["geometry"]).to_dict() for idx, row in gdf.iterrows()]
    result = geometry2tilecode(
        geometries,
        resolution,
        properties_list,
        predicate,
        compact,
        topology,
        include_properties,
    )
    if compact:
        result = tilecodecompact(result, tilecode_id="tilecode", output_format="gpd")

    file_formats = [
        "csv",
        "geojson",
        "json",
        "shapefile",
        "shp",
        "gpkg",
        "geopackage",
        "parquet",
        "geoparquet",
    ]
    output_name = None
    if output_format in file_formats:
        if isinstance(data, str):
            base = os.path.splitext(os.path.basename(data))[0]
            output_name = f"{base}2tilecode_{resolution}"
        else:
            output_name = f"tilecode_{resolution}"
    return convert_to_output_format(result, output_format, output_name)