Skip to main content

Terminal-native GIS tool for vector data

Project description

geo-tool

Terminal-native GIS tool for vector data. No QGIS, no GUI, no bloat.

Inspect, convert, reproject, filter, and visualize geospatial datasets entirely from the command line. Renders maps as Unicode braille characters directly in your terminal.

Supported Formats

Format Read Write
Shapefile Yes Yes
GeoPackage Yes Yes
GeoJSON Yes Yes
FlatGeobuf Yes Yes
TopoJSON Yes No

Installation

Requires Python 3.12+ and uv.

git clone <repo-url>
cd "GIS Terminal"
uv sync

This installs geo-tool as a CLI tool in the project's virtual environment. Run it with:

# Activate the venv first
# Linux/macOS:
source .venv/bin/activate
# Windows:
.venv\Scripts\activate

# Then use geo-tool directly
geo-tool --help

Or run without activating:

# Linux/macOS:
.venv/bin/geo-tool --help
# Windows:
.venv\Scripts\geo-tool.exe --help

Dependencies

Four runtime dependencies, all pulling from GDAL/OGR, PROJ, and GEOS under the hood:

  • click -- CLI framework
  • fiona -- vector I/O (GDAL/OGR bindings with streaming support)
  • shapely -- geometry operations (GEOS bindings)
  • pyproj -- CRS transformations (PROJ bindings)

Commands

geo-tool info -- Inspect metadata

geo-tool info countries.shp
File:      countries.shp
Driver:    ESRI Shapefile
CRS:       EPSG:4326
Geometry:  Polygon
Features:  177
Extent:    -180.000000, -90.000000, 180.000000, 83.645130

Fields:
  NAME        str
  POP_EST     int64
  GDP_MD      float
  ISO_A3      str

Machine-readable output for scripting:

geo-tool --json info countries.shp
{
  "path": "countries.shp",
  "driver": "ESRI Shapefile",
  "crs": "EPSG:4326",
  "geometry_type": "Polygon",
  "feature_count": 177,
  "bounds": [-180.0, -90.0, 180.0, 83.64513],
  "fields": [
    {"name": "NAME", "type": "str"},
    {"name": "POP_EST", "type": "int64"}
  ]
}

For multi-layer formats (GeoPackage):

geo-tool info data.gpkg --layer boundaries

geo-tool convert -- Format conversion

Convert between any supported writable formats. The output format is detected from the file extension.

# Shapefile to GeoPackage
geo-tool convert input.shp output.gpkg

# GeoJSON to FlatGeobuf
geo-tool convert input.geojson output.fgb

# Convert and reproject in one step
geo-tool convert input.shp output.geojson --crs EPSG:4326

geo-tool reproject -- Change coordinate reference system

# WGS84 to Web Mercator
geo-tool reproject input.geojson output.geojson --crs EPSG:3857

# To a UTM zone
geo-tool reproject input.shp output.gpkg --crs EPSG:32633

The --crs flag accepts any string that pyproj understands: EPSG:XXXX, WKT, or PROJ strings.

geo-tool filter -- Spatial and attribute filtering

Filter by bounding box (west, south, east, north):

geo-tool filter countries.gpkg --bbox -10,35,30,60

Filter by attribute expression (OGR SQL syntax):

geo-tool filter countries.gpkg --where "POP_EST > 50000000"

Combine both:

geo-tool filter countries.gpkg --bbox -10,35,30,60 --where "POP_EST > 10000000"

Write results to a file instead of stdout:

geo-tool filter countries.gpkg --bbox 0,0,10,10 -o subset.geojson

When no -o is given, GeoJSON is written to stdout -- pipe it wherever you want:

geo-tool filter data.gpkg --where "type = 'highway'" | jq '.features | length'

geo-tool view -- Terminal map preview

Renders geometries as Unicode braille characters directly in your terminal.

geo-tool view countries.shp

Interactive controls:

Key Action
+ Zoom in
- Zoom out
Arrows Pan
r Reset view
q Quit

For non-interactive (pipe-friendly) output:

geo-tool view countries.shp --static

Restrict the initial view to a bounding box:

geo-tool view countries.shp --bbox -20,30,45,72

How it works: Each terminal character cell is a 2x4 braille dot pattern (Unicode block U+2800). This gives 8x the pixel resolution of regular characters. An 80-column terminal renders at 160x84 effective pixels. A 200-column terminal reaches 400x192 pixels -- enough to recognize coastlines, boundaries, and road networks.

Geometries are rasterized using Bresenham's line algorithm for lines and polygon outlines. Points are drawn as small crosses. For large datasets (>10,000 features), the renderer samples features and displays a notice.

geo-tool serve -- Browser map

Opens the dataset on a Leaflet map in your browser. No external server or build step required.

geo-tool serve countries.gpkg
Serving countries.gpkg at http://localhost:8080
Press Ctrl+C to stop.

Options:

# Custom port
geo-tool serve data.geojson --port 3000

# Don't auto-open the browser
geo-tool serve data.geojson --no-open

The server uses Python's built-in http.server with Leaflet loaded from CDN. Features are spatially filtered on each map pan/zoom -- only the visible extent is sent to the browser (max 5,000 features per request). Click any feature to see its attributes in a popup.

Global Options

These go before the subcommand:

geo-tool --json info data.shp        # JSON output
geo-tool -q convert in.shp out.gpkg  # Suppress status messages
geo-tool --version                   # Show version
Flag Effect
--json Machine-readable JSON output
-q/--quiet Suppress non-essential stderr output
-v/--verbose Debug-level logging
--version Print version and exit

Piping and Scripting

geo-tool is designed to be Unix-pipe friendly. Combine commands:

# Get the CRS of a file
geo-tool --json info data.shp | python -m json.tool

# Filter then inspect the result
geo-tool filter big.gpkg --bbox 0,0,10,10 -o subset.geojson && geo-tool info subset.geojson

# Count features matching a query
geo-tool --json filter data.gpkg --where "pop > 1000000" | python -c "
import json, sys
fc = json.load(sys.stdin)
print(len(fc['features']))
"

When stdout is not a TTY (i.e., output is piped), geo-tool view automatically uses static mode.

Project Structure

src/geo/
  cli.py                  Entry point, Click command group
  formats.py              File extension to OGR driver mapping
  output.py               Human-readable and JSON formatters
  errors.py               Exception hierarchy
  commands/
    info.py               geo-tool info
    convert.py            geo-tool convert
    reproject.py          geo-tool reproject
    filter.py             geo-tool filter
    view.py               geo-tool view
    serve.py              geo-tool serve
  core/
    reader.py             Dataset opening via Fiona
    writer.py             Dataset writing via Fiona
    inspector.py          Metadata extraction
    transform.py          CRS reprojection via pyproj
    query.py              Spatial/attribute filtering via OGR
  render/
    canvas.py             Boolean pixel grid
    braille.py            Pixel-to-braille encoding
    viewport.py           Geographic-to-pixel coordinate transform
    rasterizer.py         Bresenham lines, geometry rasterization
    display.py            Interactive terminal loop
  server/
    app.py                HTTP server startup
    handler.py            Request routing and feature API
    templates.py          Leaflet HTML template

Design Decisions

  • Click over Typer -- explicit argument handling, no type-hint magic
  • Fiona over pyogrio -- streaming iteration instead of bulk memory load
  • Braille over block characters -- 8x pixel resolution per character cell
  • Leaflet over MapLibre -- 40KB from CDN, zero build step, native GeoJSON support
  • No rich/tabulate -- the tool has ~3 tables total; str.ljust() is enough
  • always_xy=True in pyproj -- prevents silent lon/lat axis swap that corrupts data
  • src/ package layout -- PyPA standard, prevents accidental local imports

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gis_terminal-0.1.0.tar.gz (6.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gis_terminal-0.1.0-py3-none-any.whl (24.1 kB view details)

Uploaded Python 3

File details

Details for the file gis_terminal-0.1.0.tar.gz.

File metadata

  • Download URL: gis_terminal-0.1.0.tar.gz
  • Upload date:
  • Size: 6.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gis_terminal-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7b34ab6e1ff9e67ed39e89c3260bbd98433cd88df34cadc8ca9f84216edb9c06
MD5 3b5cfd8cc643845a23fcf45e3db7a280
BLAKE2b-256 5841a1cc4e9968642c8d9d88de34d90d791420bb4e43b53bac49986f4a28faea

See more details on using hashes here.

File details

Details for the file gis_terminal-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gis_terminal-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for gis_terminal-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d94acfebdedfb5f544d840c218e9957dbfb685097b683454f898f303bffdf885
MD5 ad197e9dc8d667d43588bf39954e6ee5
BLAKE2b-256 aadffb5026c509a59b230f3d894dc4fb23f1f8974188562be91fd62f6c8e2e16

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page