pycsamt.gis.utils#
GIS utilities for pycsamt (v2). Provides coordinate
transformations between geographic (lat/lon) and UTM using
GDAL (preferred) or a PROJ fallback (pyproj).
Core features#
Geographic ⇄ UTM conversions (scalar and vectorized).
Flexible latitude/longitude parsing (decimal and DMS).
Small helpers for UTM zones and EPSG lookup.
Examples
>>> from pycsamt.gis.utils import project_point_ll2utm
>>> project_point_ll2utm(-118.34, 34.05)
Note
Parts of this module are adapted from the MTPy project (MTgeophysics/mtpy-v2). Original work: Krieger, L., & Peacock, J. (2014), MTpy: A Python toolbox for magnetotellurics, Computers & Geosciences, 72, 167–175, https://doi.org/10.1016/j.cageo.2014.07.013.
The implementation here has been revised, fixed, and extended for pycsamt v2, with additional validation, deprecations, and compatibility layers.
Functions
|
Validate and coerce an elevation to a floating number. |
|
Validate and coerce a latitude to decimal degrees. |
|
Validate and coerce a longitude to decimal degrees. |
Infer the coordinate system of paired |
|
|
Calculates the forward azimuth between consecutive points. |
|
Convert a decimal-degree value to |
|
Convert DMS string |
|
Convert decimal degrees to a |
|
Convert a DMS string or decimal degrees to a float. |
|
Project coordinates between two EPSG-defined CRSs. |
|
Fetches elevation from sea level for geographic coords. |
|
Fetches elevation from sea level for UTM coordinates. |
|
Get the WGS84 UTM EPSG code for a geographic coordinate. |
|
[DEPRECATED] GDAL SpatialReference → UTM string is deprecated; use 'get_utm_zone' for standard UTM formatting. |
|
Compute the UTM zone, hemisphere flag, and zone string for a geographic coordinate. |
|
Convert latitude/longitude to UTM coordinates. |
|
Resolve input pair to |
|
Transform one geographic point to UTM coordinates. |
|
Transform a UTM point to latitude/longitude. |
|
Transform latitude/longitude to UTM coordinates. |
|
Convert UTM coordinates to geographic (lat, lon) using |
|
Convert geographic coordinates to UTM using |
|
[DEPRECATED] Deprecated; will be removed in a future release. |
|
[DEPRECATED] Deprecated; will be removed in a future release. |
|
Convert UTM coordinates to latitude/longitude. |
|
Convert WGS84 (lat, lon) to UTM and verify round-trip. |
|
Resolve the WGS84 UTM EPSG code for a given UTM zone. |
- pycsamt.gis.utils.project_point_ll2utm(lat, lon, datum='WGS84', utm_zone=None, epsg=None)[source]#
Transform one geographic point to UTM coordinates.
Accepts a single point or 1-D arrays/Series of points in decimal degrees (or DMS strings) and returns UTM easting, northing, and zone. Uses GDAL/OSR when available; falls back to PROJ via
pyprojwith explicit XY order.- Parameters:
lat (float or str, array-like, or pd.Series) – Latitude in decimal degrees or sexagesimal string (
"DD:MM:SS.sss").lon (float, str, array-like, or pd.Series) – Longitude in decimal degrees or sexagesimal string (
"DD:MM:SS.sss").datum (str, default "WGS84") – Geodetic datum name (e.g.,
"WGS84","NAD83"). May also be an EPSG integer if GDAL is used.utm_zone (str, optional) – UTM zone designator like
"55S". If omitted or set to a non-string (or"none"), the zone is inferred from the input point.epsg (int, optional) – EPSG code for the projected CRS. When provided, it takes precedence over
utm_zoneanddatum.
- Returns:
For scalar input:
(easting, northing, zone). For array input: record array with fields('easting','northing','elev','utm_zone').- eastingfloat or None
UTM easting in meters, or
Nonewhen inputs areNone.
- northingfloat or None
UTM northing in meters, or
Nonewhen inputs areNone.
- zonestr or None
UTM zone string (e.g.,
"55S").Nonewhen not determinable or inputs areNone.
- Return type:
tuple or np.recarray
Notes
This variant accepts a single point. For vectorized inputs, use
project_points_ll2utm().Inputs are validated with
assert_lat_valueandassert_lon_valuebefore projection.With GDAL, transforms use
osr.CoordinateTransformation; with PROJ they usepyproj.Proj.
Notes
Enforces traditional GIS order (lon, lat) in the GDAL path to avoid invalid-latitude errors with GDAL ≥ 3.
The
pyprojpath uses a Transformer withalways_xy=Truefor the same reason.
Examples
>>> e, n, z = project_point_ll2utm(34.05, -118.34) >>> z '11S'
- pycsamt.gis.utils.project_point_utm2ll(easting, northing, utm_zone, datum='WGS84', epsg=3149)[source]#
Transform a UTM point to latitude/longitude.
Converts UTM easting/northing to geographic latitude and longitude (decimal degrees). Uses GDAL/OSR when available, else falls back to PROJ via
pyproj.- Parameters:
easting (float) – Easting in meters.
northing (float) – Northing in meters.
utm_zone (str or int) – UTM zone designator. Either a string like
"10S"or an integer UTM code (negative for south). Ignored whenepsgis provided.datum (str, default "WGS84") – Geodetic datum name (e.g.,
"WGS84","NAD27").epsg (int, optional) – EPSG code defining the projected CRS. When provided, it takes precedence over
utm_zoneanddatum. The default is3149for historical compatibility.
- Returns:
lat (float) – Latitude in decimal degrees, rounded to 6 decimals.
lon (float) – Longitude in decimal degrees, rounded to 6 decimals.
- Return type:
Notes
With GDAL, the conversion uses
osr.CoordinateTransformationto a geographic CRS cloned from the projected CRS.With PROJ, the conversion uses
pyproj.Projwithinverse=True.When
epsgrefers to a non-UTM CRS,utm_zoneis not required.The function validates
eastingandnorthingcan be cast tofloatand raisesGisErrorotherwise.
Examples
Using an explicit zone:
>>> project_point_utm2ll(377274.0, 3762150.0, "11S")
Using an EPSG code (preferred when known):
>>> project_point_utm2ll( ... 377274.0, 3762150.0, utm_zone="11S", epsg=32611 ... )
See also
project_points_ll2utmForward transform from geographic to UTM.
References
- pycsamt.gis.utils.ll_to_utm(reference_ellipsoid, lat, lon)[source]#
Convert latitude/longitude to UTM coordinates. Equations from USGS Bulletin 1532.
- Parameters:
- Returns:
utm_zone (str) – UTM zone string (e.g. ‘11N’).
easting (float)
northing (float)
- Return type:
- pycsamt.gis.utils.utm_to_ll(reference_ellipsoid, northing, easting, zone)[source]#
Convert UTM coordinates to latitude/longitude. Inverse of ll_to_utm, equations from USGS Bulletin 1532.
- pycsamt.gis.utils.get_utm_string_from_sr(spatial_ref)[source]#
[DEPRECATED] GDAL SpatialReference → UTM string is deprecated; use ‘get_utm_zone’ for standard UTM formatting.
Return a UTM zone string (e.g.,
'11N') from a GDALSpatialReference.- Parameters:
spatial_ref (osr.SpatialReference) – GDAL spatial reference object with a UTM projection.
- Returns:
UTM zone string such as
'11N'or'55S'. If a valid UTM zone is not encoded, returns'0'.- Return type:
Notes
This helper is deprecated. Prefer
get_utm_zone(), which derives a zone from latitude/longitude using the standard UTM rules.Examples
>>> # sr is an osr.SpatialReference set to a UTM CRS >>> # get_utm_string_from_sr(sr)
- pycsamt.gis.utils.get_utm_zone(latitude, longitude)[source]#
Compute the UTM zone, hemisphere flag, and zone string for a geographic coordinate.
- Parameters:
- Returns:
zone_number (int) – UTM zone number in
[1, 60].is_northern (bool) –
Truefor the northern hemisphere, elseFalse.zone_string (str) – Concatenation of zone and latitude band letter, e.g.,
'11N'.
- Return type:
Notes
Zone width is 6 degrees, starting at
-180°. Values are wrapped into[1, 60].The latitude band letter is obtained via
utm_letter_designator().
Examples
>>> get_utm_zone(34.05, -118.34)[2] '11S'
- pycsamt.gis.utils.utm_zone_to_epsg(zone_number, is_northern)[source]#
Resolve the WGS84 UTM EPSG code for a given UTM zone.
- Parameters:
- Returns:
Matching EPSG code (e.g.,
32611or32755) when found, elseNone.- Return type:
int or None
Notes
The lookup scans
EPSG_DICTfor a PROJ string that matches+zone,+datum=WGS84, and an optional+southflag for the southern hemisphere.Examples
>>> utm_zone_to_epsg(11, True) in (32611, None) True
- pycsamt.gis.utils.get_epsg(latitude, longitude)[source]#
Get the WGS84 UTM EPSG code for a geographic coordinate.
- Parameters:
- Returns:
EPSG code for the inferred UTM CRS, or
Noneif no match is found.- Return type:
int or None
Notes
This is a convenience wrapper that calls
get_utm_zone()andutm_zone_to_epsg().Examples
>>> epsg = get_epsg(34.05, -118.34) >>> epsg in (32611, 32711, None) True
- pycsamt.gis.utils.assert_xy_coordinate_system(x, y)[source]#
Infer the coordinate system of paired
xandyarrays.Heuristics detect one of three systems:
'll'— longitude/latitude in decimal degrees.'dms'— degree-minute-second stringsDD:MM:SS.'utm'— any other numeric system (fallback).
- Parameters:
x (array-like (1D)) – Arrays of horizontal (
x) and vertical (y) positions. Elements may be numeric or DMS strings.y (array-like (1D)) – Arrays of horizontal (
x) and vertical (y) positions. Elements may be numeric or DMS strings.
- Returns:
cs – Inferred coordinate system token.
- Return type:
{‘utm’, ‘dms’, ‘ll’}
Notes
DMS is detected if any array consists entirely of strings containing the
':'separator.Decimal degrees are detected when either orientation matches bounds:
|x| <= 180and|y| <= 90(lon, lat), or|x| <= 90and|y| <= 180(lat, lon).
If neither DMS nor decimal-degree bounds match, the function returns
'utm'by default.
Examples
>>> import numpy as np >>> np.random.seed(42) >>> x, y = np.random.rand(7) * 1.0, np.arange(7) * 0.1 >>> assert_xy_coordinate_system(x, y) 'll' >>> assert_xy_coordinate_system(x * 1000, y * 1000) 'utm' >>> x = ['28:24:43.08', '28:24:42.69', '28:24:42.31'] >>> y = ['109:19:58.34', '109:19:58.93', '109:19:59.51'] >>> assert_xy_coordinate_system(x, y) 'dms'
- pycsamt.gis.utils.decimal_to_dms(position)[source]#
Convert decimal degrees to a
DD:MM:SS.ssstring.- Parameters:
position (float) – Decimal degrees for latitude or longitude.
- Returns:
Sexagesimal string in
"DD:MM:SS.ss"format.- Return type:
See also
convert_position_float2strUnderlying converter used by this wrapper.
Examples
>>> decimal_to_dms(-118.34563) '-118:20:44.27'
- pycsamt.gis.utils.dms_to_decimal(position_str)[source]#
Convert a DMS string or decimal degrees to a float.
This is a convenience wrapper around
convert_position_str2float(). It accepts either a decimal degrees string/number or a sexagesimal string in'DD:MM:SS.sss'format.- Parameters:
position_str (str or float) – Coordinate in decimal degrees or DMS string.
- Returns:
Decimal degrees value, or
Nonefor invalid input.- Return type:
float or None
Examples
>>> dms_to_decimal("34:03:00") 34.05 >>> dms_to_decimal("-118.34") -118.34
- pycsamt.gis.utils.to_utm(lat: Any, lon: Any, data: Any | None = None, *, datum: str = 'WGS84', utm_zone: str | None = None, epsg: int | None = None, as_frame: Literal[True]) DataFrame[source]#
- pycsamt.gis.utils.to_utm(lat: float, lon: float, data: Any | None = None, *, datum: str = 'WGS84', utm_zone: str | None = None, epsg: int | None = None, as_frame: Literal[False] = False) tuple[float, float, str | None]
- pycsamt.gis.utils.to_utm(lat: Sequence[Any] | NDArray[float64], lon: Sequence[Any] | NDArray[float64], data: Any | None = None, *, datum: str = 'WGS84', utm_zone: str | None = None, epsg: int | None = None, as_frame: Literal[False] = False) tuple[NDArray[float64], NDArray[float64], NDArray[object]]
Convert geographic coordinates to UTM using
project_point_ll2utm().Accepts flexible latitude/longitude inputs (scalars, arrays, pandas Series, or column names referencing a passed
dataframe). Returns either arrays/tuples or aDataFramewith original and UTM fields.- Parameters:
lat (float, str, array-like, or pd.Series) – Geographic coordinates in decimal degrees or DMS strings. If a string is given, it is treated as a column name and
datamust be provided.lon (float, str, array-like, or pd.Series) – Geographic coordinates in decimal degrees or DMS strings. If a string is given, it is treated as a column name and
datamust be provided.data (pd.DataFrame, optional) – Source of columns when
latorlonare strings.datum (str, default "WGS84") – Datum name or EPSG (int) accepted by the underlying transformer.
utm_zone (str, optional) – UTM zone (e.g.,
"11S"). If absent, it is inferred from the input centroid (or per-point for scalar).epsg (int, optional) – EPSG code for the projected CRS. Overrides
utm_zonewhen provided.as_frame (bool, default False) – If
True, return a pandasDataFramewith columns['lat','lon','easting','northing','zone']. IfFalse, return(easting, northing, zone)as arrays (or scalars for scalar inputs).
- Returns:
When
as_frame=True, a frame with original and UTM columns. Otherwise a tuple(e, n, zone)where each element matches the input shape (scalar or 1-D array).- Return type:
Notes
Parsing of DMS strings and range checks are handled by the underlying projection helper.
For array inputs, this function preserves order and length; indices are preserved when built from
data[<col>]andas_frame=True.
Examples
Scalar input:
>>> to_utm(34.05, -118.34) (..., ..., '11S')
From a DataFrame:
>>> # df has columns 'lat_deg' and 'lon_deg' >>> # to_utm('lat_deg','lon_deg', data=df, as_frame=True) ...
- pycsamt.gis.utils.to_ll(easting: Any, northing: Any, zone: Any | None = None, data: Any | None = None, *, datum: str = 'WGS84', epsg: int | None = None, as_frame: Literal[True]) DataFrame[source]#
- pycsamt.gis.utils.to_ll(easting: float, northing: float, zone: Any | None = None, data: Any | None = None, *, datum: str = 'WGS84', epsg: int | None = None, as_frame: Literal[False] = False) tuple[float, float]
- pycsamt.gis.utils.to_ll(easting: Sequence[float] | NDArray[float64], northing: Sequence[float] | NDArray[float64], zone: Sequence[Any] | NDArray[object] | None = None, data: Any | None = None, *, datum: str = 'WGS84', epsg: int | None = None, as_frame: Literal[False] = False) tuple[NDArray[float64], NDArray[float64]]
Convert UTM coordinates to geographic (lat, lon) using
project_point_utm2ll().Accepts flexible inputs (scalars, arrays, Series, or column names referencing a provided DataFrame). Returns a tuple or a DataFrame with original and converted fields.
- Parameters:
easting (float, array-like, or pd.Series) – UTM coordinates in meters. When strings are given, they are treated as column names in
data.northing (float, array-like, or pd.Series) – UTM coordinates in meters. When strings are given, they are treated as column names in
data.zone (str, int, array-like, or pd.Series, optional) – UTM zone designator (e.g.,
"11S") or signed UTM code (negative for south). If strings are given, they are treated as column names indata. May be omitted whenepsgis provided.data (pd.DataFrame, optional) – Source of columns when any of the inputs are strings.
datum (str, default "WGS84") – Datum name for GDAL-backed paths.
epsg (int, optional) – EPSG code that defines the projected CRS. When set, it takes precedence and
zoneis not required.as_frame (bool, default False) – If
True, return a DataFrame with columns['easting','northing','zone','lat','lon']. Otherwise, return(lat, lon)as scalars or arrays.
- Returns:
A DataFrame when
as_frame=True; otherwise a tuple(lat, lon)matching the input shape.- Return type:
Notes
Index is preserved when inputs originate from a Series or from
data[<column>]withas_frame=True.When arrays are given and
epsgis used, the same EPSG applies to all rows.zonemay be a scalar or an array/Series matching the shape ofeastingandnorthing.
Examples
Scalars:
>>> to_ll(377274.0, 3762150.0, "11S") (34.05, -118.34)
From a DataFrame:
>>> # df has 'E', 'N', 'zone' columns >>> # to_ll('E','N','zone', data=df, as_frame=True) ...
- pycsamt.gis.utils.normalize_lat_lon(a: float | str, b: float | str, *, assume: Literal['lonlat', 'latlon', 'auto'] = 'lonlat', error: Literal['ignore', 'raise'] = 'ignore', clip: bool = False) tuple[float, float][source]#
- pycsamt.gis.utils.normalize_lat_lon(a: Sequence[float | str], b: Sequence[float | str], *, assume: Literal['lonlat', 'latlon', 'auto'] = 'lonlat', error: Literal['ignore', 'raise'] = 'ignore', clip: bool = False) tuple[ndarray, ndarray]
Resolve input pair to
(lat, lon)regardless of order.Accepts values in either legacy order (lat, lon) or the new expected order (lon, lat). Returns a tuple in the canonical order
(lat, lon)and avoids common|Latitude| > 90errors by swapping when clear.- Parameters:
a (float or str, or 1-D sequences) – Coordinate components. Strings may be decimal or DMS (
"DD:MM:SS"). Sequences must be same length.b (float or str, or 1-D sequences) – Coordinate components. Strings may be decimal or DMS (
"DD:MM:SS"). Sequences must be same length.assume ({"lonlat","latlon","auto"}, default "lonlat") –
Tie-break for ambiguous pairs (both
|val| <= 90)."lonlat": treat input as (lon, lat)."latlon": treat input as (lat, lon)."auto": prefer (lon, lat) when ambiguous.
error ({"ignore","raise"}, default "ignore") – On impossible pairs (both
|val| > 90or both|val| > 180), either raise or return ``nan``s.clip (bool, default False) – If
True, clip lat to [-90, 90] and lon to [-180, 180] when slightly out-of-range.
- Returns:
lat, lon – Coordinates in canonical order.
- Return type:
float or ndarray
Notes
Heuristics:
If one value is in (90, 180] and the other in [-90, 90], the former is lon and the latter is lat.
If both are
|val| <= 90, useassume.Values with
|val| > 180are invalid unlessclip.