Skip to main content

AI-ready GIS toolkit for energy and subsurface workflows.

Project description

env-able

An open source spatial analysis library built for AI-driven GIS workflows. Designed to give AI systems like Claude reliable, hallucination-free tools for spatial operations in energy and subsurface contexts.

Install

pip install env-able

# with Databricks support
pip install env-able[databricks]

# with interactive map server (Atlas)
pip install env-able[atlas]

# with large-scale streaming pulls (DuckDB)
pip install env-able[fast]

Usage

import env_able as env

Functions

env.pull(table, output=None, wkt_col=None, chunk_size=None, crs="EPSG:4326")

Pull a Databricks table or query to a local file, chunking around the row/byte limit automatically.

Databricks caps result sets (~4 096 rows for narrow tables, fewer when WKT columns are present). pull() paginates with LIMIT/OFFSET, assembles the complete dataset in memory, and writes it to disk in the requested format.

Parameters

  • table — fully-qualified table name (catalog.schema.table) or a complete SELECT query
  • output — destination file path; format inferred from extension (.gpkg, .geojson, .shp, .parquet, .csv, .xlsx). Omit to return a GeoDataFrame or DataFrame.
  • wkt_col — column containing WKT geometry strings. Auto-detected if omitted.
  • chunk_size — rows per Databricks query. Defaults to 512 (WKT) or 4 096 (tabular). Reduce if you hit payload errors on wide tables.
  • crs — CRS to assign geometry. Default EPSG:4326.

Environment variables required

DATABRICKS_HOST       # https://adb-<workspace-id>.azuredatabricks.net
DATABRICKS_TOKEN      # personal access token
DATABRICKS_HTTP_PATH  # /sql/1.0/warehouses/<warehouse-id>
import env_able as env

# pull a full table to GeoPackage
env.pull("catalog.schema.wells", "wells.gpkg")

# pull with a filter query
env.pull("SELECT * FROM catalog.schema.wells WHERE state = 'TX'", "wells_tx.gpkg")

# pull tabular (no geometry)
env.pull("catalog.schema.formations", "formations.csv")

# return in-memory without writing
gdf = env.pull("catalog.schema.leases", wkt_col="geom_wkt", crs="EPSG:4269")

env.Intersect(input_layer, intersect_layer, output=None)

Computes geometric intersection of input features against a polygon boundary.

  • input_layer — point, line, or polygon (file path or GeoDataFrame)
  • intersect_layer — polygon layer defining the intersection boundary
  • output — file path to save result (.gpkg, .shp, etc.) — omit to return a GeoDataFrame
import env_able as env
env.Intersect("wells.shp", "boundary.shp", "result.gpkg")

env.Buffer(input_layer, distance, unit="meters", output=None)

Buffers input features by a given distance and unit.

  • input_layer — point, line, or polygon (file path or GeoDataFrame)
  • distance — numeric buffer distance
  • unitmeters, km, miles, feet, usfeet, nautical miles
  • output — file path to save result — omit to return a GeoDataFrame
env.Buffer("wells.shp", 1, "miles", "wells_buffer.gpkg")

env.Clip(input_layer, clip_layer, output=None)

Clips input features to the extent of a polygon clip boundary.

  • input_layer — point, line, or polygon (file path or GeoDataFrame)
  • clip_layer — polygon layer defining the clip boundary
  • output — file path to save result — omit to return a GeoDataFrame
env.Clip("roads.shp", "county.shp", "roads_clipped.gpkg")

env.morph(input_path, output_path, **kwargs)

Universal format translation. Converts between shp, gpkg, gdb, csv, xlsx, xls, dbf, geojson, json with automatic CRS handling, field name fixes, and multi-layer support.

  • input_path — source file or geodatabase
  • output_path — destination file. Extension sets the format. Use trailing / for directory output (one file per layer). Use dot notation for named layers: roads.parcels.gpkg
  • x_col, y_col — column names for X/Y coordinates (auto-detected if not provided)
  • wkt_col — column containing WKT geometry (auto-detected if not provided)
  • crs — coordinate reference system e.g. EPSG:4326 (required for tabular → spatial)
env.morph("roads.shp", "roads.gpkg")
env.morph("county.gdb", "county.gpkg")
env.morph("county.gdb", "output_folder/")
env.morph("owners.csv", "owners.geojson", crs="EPSG:4269")
env.morph("owners.csv", "owners.shp", x_col="LONGITUDE", y_col="LATITUDE", crs="EPSG:4269")
env.morph("roads.gpkg", "roads.parcels.gpkg")
env.morph("data.json", "data.gpkg")

Smart behavior:

  • GDB / GPKG with multiple layers → detects all layers automatically
  • CRS mismatch → auto-reprojects
  • Shapefile field name limit (10 chars) → auto-truncates with warnings
  • Invalid output path → plain English error
  • Empty layers → skipped with a warning, not a crash

env.atlas — interactive map server

env.atlas launches a browser-based interactive map (MapLibre GL JS) that Claude can load data into and control programmatically. The user opens it in their browser and fine-tunes from there.

Requires pip install env-able[atlas]

import env_able as env

# Start the server (non-blocking — runs in background thread)
env.atlas.serve(block=False)

# Connect and operate
client = env.atlas.connect()
client.add_layer(gdf, "Wells", color="#f5a623")   # push a GeoDataFrame
client.set_viewport([-103.0, 32.0], zoom=7)       # frame the view
print(client.state())                              # check what's on the map
client.save_layout("wells_map.atlas.json")         # save for later

AtlasClient methods:

Method Description
add_layer(data, name, color) Push GeoDataFrame or file path; serializes inline, no temp file
upload_layer(path, name, color) Load any format (gpkg, geojson, csv, xlsx, zip/shp); converts via morph
remove_layer(name) Remove a layer by name
clear() Remove all layers
set_layer_color(name, color) Change a layer's color; browser updates on next poll
reorder_layers(names) Set rendering order — first name = top of map
validate_join(input_layer, input_field, join_source, join_field) Preview join match stats without modifying any layer
join_field(input_layer, input_field, join_source, join_field, fields=None) Left-join attributes from a loaded layer or table into another layer; fields limits which columns are added
set_viewport(center, zoom) Set map view — browser flies there within ~2 s
get_viewport() Read current viewport (reflects user pan/zoom)
state() Layer count, names, colors, feature counts, current viewport
save_layout(path) Write full map state to .atlas.json
load_layout(path) Restore a saved layout
export_svg(path) Export all data layers as a vector SVG (no basemap)
is_running() Health check

The browser UI includes an ArcGIS Pro-style ribbon with basemap switching, file upload, and PNG/PDF export, plus a layer panel with drag-and-drop reorder, color picker (server-synced), visibility toggle, zoom-to, and remove.


env.stream — large-scale Databricks pulls

env.stream pages arbitrarily large tables through DuckDB without holding them in RAM, writing directly to GPKG, GeoJSON, Parquet, or CSV. Bypasses the ~4096-row / ~2 MB Databricks response cap.

Requires pip install env-able[fast]

from env_able.stream import pull_to_file, connector_arrow_frames

# Stream a full table to GeoPackage via Arrow (no row cap)
frames = connector_arrow_frames(
    "SELECT * FROM catalog.schema.wells",
    host="https://adb-xxxx.azuredatabricks.net",
    http_path="/sql/1.0/warehouses/xxxx",
    token="dapixxxx"
)
rows = pull_to_file(frames, "wells.gpkg", wkt_col="geom_wkt")
print(f"{rows:,} rows written")

Transports:

Function Method Cap
connector_arrow_frames Databricks SQL connector Arrow batches None
rest_external_links_frames Statement Execution API, Cloud Fetch None
keyset_frames Seek/keyset pagination Configurable page size
offset_frames LIMIT/OFFSET pagination Configurable page size

Changelog

v0.8.4 — 2026-07-21

  • client.join_field() — programmatic left-join: carry attributes from any loaded layer or table into another layer in-place; optional fields list to limit what's added; mirrors the Atlas UI Join Field tool
  • client.validate_join() — preview match stats (input features, matched, unmatched, join table rows, duplicate key flag) without modifying any layer
  • Join Field UI — field checkboxes — "Fields to Join" section with Select All / Deselect All; join key column auto-excluded
  • Join Source excludes Input Layer — prevents joining a layer to itself
  • ArcGIS Pro-style validation panel — two-section stats table (Input Layer / Join Table) with many-to-one key count
  • SVG exportclient.export_svg(path) + browser Export ribbon SVG button; pure vector, no basemap, no raster dependencies

v0.8.0 — 2026-07-17

  • Multi-file shapefile upload — select .shp + companions together; GDAL finds .prj/.dbf/.shx automatically
  • SHAPE_RESTORE_SHX — missing .shx regenerated on upload instead of failing
  • Layer right-click menu — Rename (inline), Zoom To, Attribute Table, Remove
  • GET /api/layers/{name}/attributes REST endpoint for tabular attribute data
  • Folder drag-and-drop — drag a shapefile folder from Explorer onto the map
  • File picker "All Files" — no more "Custom" filter in Windows dialog
  • CRS prompt modal — manual EPSG/WKT override when CRS cannot be detected
  • CRS fix — removed false EPSG:3857 detection; only EPSG:4326 (decimal degrees) is inferred automatically
  • ESRI WKT fallback_try_read_prj() handles non-standard ESRI projection names via pyproj → GDAL osr → regex parameter extraction

v0.6.0 — 2026-07-17

  • Browser file upload (Add Layer button) — gpkg, geojson, zip/shp, csv/xlsx, kml
  • Layer drag-and-drop reorder in the panel; MapLibre z-order rebuilds live
  • Color picker now syncs back to server on commit; Claude can read user color changes
  • client.upload_layer(path), client.set_layer_color(name, color), client.reorder_layers(names)
  • Bidirectional poll — Claude's remove_layer() and set_layer_color() now reflect in browser without refresh
  • python-multipart added to atlas extras

v0.5.1 — 2026-07-15

  • AtlasClientenv.atlas.connect() returns a programmatic client for Claude to operate Atlas without writing Python files
  • client.add_layer, set_viewport, save_layout, load_layout, state and more
  • Browser viewport sync — Claude sets view, browser flies to it; user pan/zoom pushed back to server
  • Export ribbon tab — Save PNG and Save PDF
  • serve(block=False) for non-blocking server startup
  • Windows cp1252 fix, env.atlas lazy import fix

v0.5.0 — 2026-07-15

  • env.stream — memory-flat streaming pulls into DuckDB; bypasses Databricks row/size caps
  • pull_to_file, connector_arrow_frames, rest_external_links_frames, keyset_frames, offset_frames
  • pip install env-able[fast] extras group (duckdb + requests)
  • Default I/O engine switched to pyogrio

v0.4.0 — 2026-07-15

  • env.atlas — interactive MapLibre map server (env.atlas.serve(), add_layer, remove_layer, clear_layers)
  • ArcGIS Pro-style ribbon UI with basemap switcher (7 options) and layer panel
  • pip install env-able[atlas] extras group

v0.3.0 — 2026-07-14

  • pull() — paginated Databricks table fetch with WKT auto-detection and chunked assembly

v0.2.0 — 2026-07-14

  • Renamed import alias convention from e to env

v0.1.0 — 2026-07-14

  • Initial release: Intersect(), Buffer(), Clip(), morph()
  • Smart geometry detection for WKT and lat/lon columns
  • Multi-layer GDB/GPKG support

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

env_able-0.9.1.tar.gz (68.2 kB view details)

Uploaded Source

Built Distribution

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

env_able-0.9.1-py3-none-any.whl (68.8 kB view details)

Uploaded Python 3

File details

Details for the file env_able-0.9.1.tar.gz.

File metadata

  • Download URL: env_able-0.9.1.tar.gz
  • Upload date:
  • Size: 68.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for env_able-0.9.1.tar.gz
Algorithm Hash digest
SHA256 2f06708d9a58140ab060c320006ebad69add0c93ffd0b134d7848a0d6fdba6a8
MD5 f8ca143eee33d72e55d590fac37e9f34
BLAKE2b-256 3f30e977d2ab564f2d678004ec184d33eb0f268da58354cd0e642df6ea1f223c

See more details on using hashes here.

File details

Details for the file env_able-0.9.1-py3-none-any.whl.

File metadata

  • Download URL: env_able-0.9.1-py3-none-any.whl
  • Upload date:
  • Size: 68.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for env_able-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2d59951231e4cec0d8c491b943b98009265771db2cb80504be12d77366987527
MD5 6fab462fcfb774fc2c52ae3181869d36
BLAKE2b-256 abe0a8fbe8782b234e9d09ea3f8e5d6b89a57abfa3ea53b4abe9e0e97ea974b3

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