-
Notifications
You must be signed in to change notification settings - Fork 104
Geospatial
Tier: Intermediate
Commands covered: geocode, geoconvert
Per-command flag reference lives in
/docs/help/. This page is the workflow layer — when to reach for each command and how they compose.
Two commands, big footprint. geocode handles forward geocoding, reverse geocoding, city suggestions, IP geolocation, and country info — all against a local Geonames index plus an optional MaxMind GeoLite2 database. No network round-trip per row, 360,000 records / sec with caching and multithreading. It can also geocode online via the OpenCage API (the opencage / opencagenow subcommands) when you need true street-address geocoding that the local city index can't do.
geoconvert flips between CSV and spatial formats (GeoJSON, SHP, KML, GPX, …).
| If you want to… | Use | Notes |
|---|---|---|
| Find lat/lon from a city name | geocode suggest |
Jaro-Winkler fuzzy matching |
| Find the nearest city to a lat/lon | geocode reverse |
Local index; no API rate limits |
| Find country code from an IP | geocode iplookup |
Needs MaxMind GeoLite2-City.mmdb |
| Enrich with US state/county FIPS codes |
geocode suggest / reverse with FIPS dyncols |
Census data prep |
| Geocode a full street address (online) | geocode opencage |
OpenCage API; needs an API key |
| Reverse-geocode a coordinate to a full address (online) | geocode opencage |
Same subcommand; mode auto-detected |
| Manage / prune the OpenCage result cache | geocode cache-* |
cache-clear, cache-prune, cache-info
|
| CSV → GeoJSON for QGIS / web maps | geoconvert |
Specify --geometry for WKT or lat/lon |
| GeoJSON / SHP → CSV | geoconvert |
Drops to a flat tabular form |
Twelve subcommands; the big four are suggest, suggestnow, reverse, reversenow. Plus iplookup / iplookupnow, countryinfo / countryinfonow, the online opencage / opencagenow subcommands, the geocode index-* subcommands for managing the local Geonames cities index, and the geocode cache-* subcommands for managing the on-disk OpenCage result cache.
# Downloads the prebuilt Geonames cities15000 index (~26k cities, pop > 15k)
qsv geocode suggest --help # first run triggers the download
# Manage the local index
qsv geocode index-check # show index metadata; check for updates
qsv geocode index-update # rebuild from the latest Geonames data
qsv geocode index-load my_index.rkyv # load a custom-built .rkyv index file
qsv geocode index-reset # restore the default prebuilt cities15000 indexFor IP-based lookups, manually download GeoLite2-City.mmdb from your MaxMind account (free) and copy it to ~/.qsv-cache/ (or set QSV_GEOIP2_FILENAME).
Example: enrich a list of city names with coordinates
# input has a "city" column with values like "Brooklyn", "san jose", "PARIS"
qsv geocode suggest city \
--new-column 'lat,lon' \
--formatstr "%latitude,%longitude" \
cities.csv > cities_with_coords.csvExample: US-only suggestion that also pulls FIPS codes (for Census joins)
qsv geocode suggest city_col --country US -f \
"%dyncols: {geocoded_city:name},{state:admin1},{county:admin2},\
{state_fips:us_state_fips_code},{county_fips:us_county_fips_code}" \
voters.csv -o voters_with_fips.csvThe %dyncols: directive expands to multiple new columns named on the left of each : pair.
Example: reverse-geocode NYC 311 lat/lon to Borough / NTA
qsv geocode reverse 'Location' \
--new-column 'nearest_city,admin1,admin2' \
--formatstr "%name,%admin1,%admin2" \
--country US \
NYC_311_SR_2010-2020-sample-1M.csv > nyc311_reversed.csvLocation is the source column in "lat, lon" or "(lat, lon)" format.
Example: reverse-geocode FIPS codes for downstream Census tract joins
qsv geocode reverse coordinate_col --country US -f \
"%dyncols: {city:name},{state:admin1},{county:admin2},\
{state_fips:us_state_fips_code},{county_fips:us_county_fips_code}" \
events.csv -o events_with_fips.csvFor ad-hoc one-off lookups from the command line (not a CSV):
qsv geocode suggestnow "Brooklyn"
qsv geocode reversenow "40.6782, -73.9442"
qsv geocode countryinfonow USNeeds the MaxMind GeoLite2-City.mmdb.
qsv geocode iplookup --new-column country ip_col logs.csv > logs_with_country.csvqsv geocode countryinfo country_code visitors.csv > with_country_info.csv
# Adds columns: name, capital, area, population, languages, currency, ...suggest / reverse are city-level and offline — fast, but they can't resolve a full street address. When you need real address geocoding, opencage calls the online OpenCage API. One subcommand does forward (address → coordinates) and reverse (coordinates → address) geocoding — the mode is auto-detected per row (pass --reverse to force reverse).
Requires an OpenCage API key — set it with --api-key or the QSV_OPENCAGE_API_KEY environment variable. A free key allows 2,500 requests/day: https://opencagedata.com/users/sign_up.
# forward-geocode a column of street addresses to coordinates
qsv geocode opencage address --new-column coordinates -f %location addresses.csv
# reverse-geocode "(lat, lon)" coordinates to a full formatted address (the default format)
qsv geocode opencage Location --reverse --new-column address events.csv
# pull individual OpenCage components with dotted dynamic formatting
qsv geocode opencage address -f '{components.city}, {components.country}' addresses.csv
# add multiple columns in one pass with the %dyncols: directive
qsv geocode opencage address \
-f '%dyncols: {city:components.city}, {postcode:components.postcode}, {tz:annotations.timezone.name}' \
addresses.csv
# one-off lookups from the shell
qsv geocode opencagenow "1600 Pennsylvania Ave NW, Washington DC"
qsv geocode opencagenow "40.71427, -74.00597"OpenCage's terms of service permit caching, so results are kept in a persistent on-disk cache (separate from the Geonames index, in {cache-dir}/geocode-opencage_v1) — re-runs and duplicate queries never re-hit the API (--cache-ttl sets the TTL; --no-cache disables it). Rows are processed sequentially behind a rate limiter (--rate-limit, default 1 request/sec — the free-tier limit), so reach for opencage for enrichment quality and for the offline subcommands for raw throughput. Inspect and clean up that cache with the cache-* subcommands.
OpenCage --formatstr options: %formatted (default — the full formatted address), %lat-long, %location, %city, %state, %county, %country, %country_name, %postcode, %confidence, %json, %pretty-json; plus dotted dynamic keys {components.<name>} and {annotations.<dotted.path>}. The %dyncols: directive works here too — %dyncols: {city:components.city}, {tz:annotations.timezone.name} adds several columns to the output CSV in one pass (it cannot be combined with --new-column).
The opencage / opencagenow subcommands keep their results in a persistent on-disk cache that lives in {cache-dir}/geocode-opencage_v1 (default cache dir ~/.qsv-cache/). It is only populated by the OpenCage subcommands — the Geonames cities index is managed separately via index-*. Three subcommands manage this cache:
# wipe the entire OpenCage cache
qsv geocode cache-clear
# delete entries older than a relative age (s/m/h/d/w suffix) or an absolute date
qsv geocode cache-prune --older-than 30d
qsv geocode cache-prune --older-than 2025-01-01
# report the cache dir, entry count, on-disk size and oldest/newest timestamps (JSON)
qsv geocode cache-infocache-prune is the tool for honoring data-retention policies without discarding the whole cache; cache-info emits a JSON summary you can pipe into other commands.
See also: /docs/help/geocode.md, Geonames, MaxMind GeoLite2, OpenCage API, Recipe: Geographic Enrichment, Lookup Tables — for fallback when geocode misses.
Convert between CSV/SVG and spatial formats. Available formats include geojson, shp (Shapefile), kml, gpx, geojsonl, and more — check qsv geoconvert --help for the full list in your build.
Example: GeoJSON → CSV (for SQL analysis)
qsv geoconvert nta_boundaries.geojson geojson csv > nta.csv
qsv sqlp nta.csv "SELECT borough, COUNT(*) FROM nta GROUP BY borough"Example: CSV with WKT geometry → GeoJSON for a web map
qsv geoconvert parcels.csv csv geojson --geometry geometry > parcels.geojsonExample: SHP → CSV (drops to tabular form)
qsv geoconvert nyc_boroughs.shp shp csv > nyc_boroughs.csvExample: pick a file via dialog, then convert
qsv prompt -m 'Choose a GeoJSON file' -F geojson \
| qsv geoconvert - geojson csv > result.csvExample: combine geocode + geoconvert to enrich and map
# 1. Reverse-geocode NYC 311 to get the borough column
qsv geocode reverse 'Location' --new-column 'borough' \
--formatstr "%admin2" --country US nyc311.csv > step1.csv
# 2. Bulk-convert lat/lon pairs into WKT, then to GeoJSON
qsv apply operations wkt_point Latitude Longitude \
--new-column geometry step1.csv > step2.csv
qsv geoconvert step2.csv csv geojson --geometry geometry > nyc311.geojsonSee also: /docs/help/geoconvert.md, geocode, Conversion & I/O.
- Command Reference (index)
- Conversion & I/O — broader I/O context
- HTTP & Web — when you need API-based geocoding (e.g., Google, Mapbox) instead of local
- Cookbook → Geographic Enrichment
- Lookup Tables — fallback patterns for unmatched rows
- Performance Tuning — multithreading & caching
qsv — GitHub · Releases · Discussions · qsv pro · Try it online · Benchmarks · datHere · DeepWiki · Dual-licensed MIT / Unlicense
Edit this page: Contributing to the Wiki
Home · Why qsv? · Tier legend
- All Commands (index)
- Selection & Inspection
- Transform & Reshape
- Aggregation & Statistics
- Joins & Set Ops
- SQL & Polars
- Validation & Schema
- Conversion & I/O
- Geospatial
- HTTP & Web
- Scripting (Luau / Python)
- Indexing, Compression & Diff
- AI & Documentation