coordshift 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+ This project follows [Semantic Versioning](https://semver.org/).
7
+
8
+ ---
9
+
10
+ ## [Unreleased]
11
+
12
+ ## [0.2.0] - 2026-03-29
13
+
14
+ **Breaking (Python / CLI):** Preset aliases (`wgs84`, `nad83`, `indiana-east`, etc.), the
15
+ `coordshift list-crs` command, and the `coordshift.presets` module are removed. Use EPSG codes,
16
+ PROJ strings, and `coordshift search` / `search_crs()` instead. The browser app (`coordshift.html`)
17
+ still ships an embedded CRS catalog. This release also includes the browser improvements and fixes
18
+ listed below.
19
+
20
+ ### Removed
21
+
22
+ - **Python / CLI:** Built-in CRS name presets (`wgs84`, `nad83`, `indiana-east`, etc.), the
23
+ **`coordshift.presets`** module, and the **`coordshift list-crs`** command. Pass **EPSG
24
+ codes**, **PROJ strings**, or other PROJ-resolvable text; use **`coordshift search`** /
25
+ **`search_crs()`** to look up USA EPSG entries by keyword. The **`coordshift.html`** browser
26
+ app still embeds a full client-side catalog.
27
+
28
+ ### Added
29
+
30
+ - `coordshift.html`: **NAD83(2011) geographic lat/lon (EPSG:6318)** added to the global CRS
31
+ catalog. This is the reference frame reported by RTK GNSS receivers observing against U.S.
32
+ CORS networks — the correct source CRS for most professional survey fieldwork in the USA.
33
+ Previously users had to substitute WGS 84 (EPSG:4326), which introduces an unmodeled ~1 m
34
+ datum shift.
35
+
36
+ - `coordshift.html`: **Datum-accuracy warnings** now appear in amber below the CRS selectors
37
+ whenever a conversion pair involves frames that differ by more than a few centimetres but
38
+ cannot be rigorously transformed by proj4.js:
39
+ - *NAD83(2011) ↔ ITRF2014* — warns of the ~1 m (~4 ft) CONUS offset caused by 30+ years
40
+ of North American tectonic plate motion since the 1992 NAD83 adjustment epoch (requires
41
+ NADCON5 or a 14-parameter Helmert transformation).
42
+ - *WGS 84 ↔ ITRF2014* — warns that the shift is <2 cm for current WGS 84 (G2139) but
43
+ still cannot be modelled; directs users to EPSG:6318 if they actually need NAD83↔ITRF.
44
+
45
+ ### Fixed
46
+
47
+ - `coordshift.html`: **Output sample rings now appear on the map preview for projected target
48
+ CRS** (State Plane, UTM, Web Mercator, etc.). Previously, the preview only plotted rings
49
+ when the converted output coordinates fell inside the lat/lon bounding box (±90°/±180°);
50
+ projected metre/foot values always failed that check and no rings appeared. The preview now
51
+ uses `toLeafletLatLng()` (the same back-projection path the full Convert handler uses),
52
+ which reprojects converted output back to WGS 84 before plotting. Rings now land on the blue
53
+ input dots for any CRS when the conversion is correct, and drift visibly when the wrong CRS
54
+ is chosen.
55
+
56
+ - `coordshift.html`: **Projected coordinate sample values shown in status bar** alongside the
57
+ ring count when the target CRS is a projected system, so users can verify numeric output
58
+ (e.g. `Projected: 192222.47 m, 501034.12 m`) without having to click an individual ring.
59
+
60
+ - `coordshift.html`: `toLeafletLatLng()` now treats NAD83(2011) (EPSG:6318) and ITRF2014
61
+ (EPSG:9000) as directly-plottable geographic CRS alongside WGS 84, avoiding an unnecessary
62
+ proj4 round-trip that could fail if the EPSG definition had not yet been fetched from
63
+ epsg.io.
64
+
65
+ ---
66
+
67
+ ## [0.1.2] - 2026-03-29
68
+
69
+ Browser app improvements only; Python library and CLI unchanged.
70
+
71
+ ### Added
72
+
73
+ - `coordshift.html`: **State Plane zones** help callout in the sidebar with a direct link to the
74
+ [USA State Plane Zones NAD83](https://hub.arcgis.com/datasets/esri::usa-state-plane-zones-nad83/)
75
+ Esri Hub map so users can look up SPCS zone names (e.g. Indiana East) and confirm the correct
76
+ zone for their project location. Link opens in a new tab (`target="_blank"`) so the app page is
77
+ not lost.
78
+
79
+ ### Changed
80
+
81
+ - `coordshift.html`: default map view now centers on the geographic center of the contiguous U.S.
82
+ (39.83°N, 98.58°W, zoom 4 / full lower-48 view) instead of Indiana. After a conversion the map
83
+ still auto-fits to the plotted points.
84
+
85
+ ---
86
+
87
+ ## [0.1.1] - 2026-03-28
88
+
89
+ Documentation and packaging metadata only; runtime code unchanged.
90
+
91
+ ### Changed
92
+
93
+ - README and `docs/examples.md`: PyPI as the primary install path.
94
+ - `pyproject.toml`: `[project.urls]` for PyPI project page links.
95
+
96
+ ---
97
+
98
+ ## [0.1.0] - 2026-03-28
99
+
100
+ Initial alpha release.
101
+
102
+ > **Alpha software.** Always verify converted coordinates against a trusted independent source.
103
+ > The authors provide no warranty and accept no liability for errors in conversion results.
104
+
105
+ ### Added
106
+
107
+ **Python library**
108
+
109
+ - `coordshift.core.convert()` — reads a CSV, reprojects coordinate columns, and returns a pandas DataFrame. Supports in-place replacement or new columns via `suffix`.
110
+ - `coordshift.core.transform_points()` — low-level list-to-list coordinate transform using `pyproj.Transformer` with `always_xy=True`.
111
+ - `coordshift.crs.resolve_crs()` — resolves EPSG codes, PROJ strings, and (in early releases) preset names to a canonical CRS string.
112
+ - `coordshift.crs.search_crs()` — searches the EPSG database by keyword (USA-filtered).
113
+ - `coordshift.crs.CRSError` — custom exception for unresolvable CRS inputs.
114
+ - `coordshift.io.read_csv()` / `write_csv()` — thin wrappers around pandas CSV I/O.
115
+ - `coordshift.io.detect_columns()` — auto-detects X/Y columns from common name patterns (lon, lat, easting, northing, x, y, etc.).
116
+ - `coordshift.presets` / `PRESETS` — built-in friendly name → EPSG mappings *(module removed in a later release)*.
117
+
118
+ **CLI** (`coordshift` entry point)
119
+
120
+ - `coordshift convert` — convert a CSV file from one CRS to another.
121
+ - `coordshift search` — search EPSG entries by keyword.
122
+ - `coordshift list-crs` — list built-in preset aliases *(removed in a later release)*.
123
+ - UTF-8 console output on Windows.
124
+ - Progress indication for large files (>10k rows).
125
+
126
+ **Browser app**
127
+
128
+ - `coordshift.html` — standalone single-file browser-based converter.
129
+ - CSV upload with automatic column detection.
130
+ - CRS search across a full NAD83(2011) State Plane, UTM, and geographic catalog.
131
+ - In-browser reprojection via proj4js (no server required, works offline).
132
+ - Leaflet map preview of converted points.
133
+ - CSV download.
134
+
135
+ **Developer tooling**
136
+
137
+ - `scripts/gen_nad83_2011_spcs_js.py` — fetches and formats the NAD83(2011) SPCS catalog as JSON.
138
+ - `scripts/merge_spcs_into_index.py` — embeds the generated JSON catalog into `coordshift.html`.
139
+
140
+ ### Distribution
141
+
142
+ - Published on PyPI as [`coordshift`](https://pypi.org/project/coordshift/) (`pip install coordshift`).
143
+
144
+ ### Design notes
145
+
146
+ - Original X/Y columns are always preserved in output. Converted values are written to new columns placed immediately after the originals (e.g. `lon` → `lon_converted`, `lat` → `lat_converted`).
147
+ - `--suffix` / `suffix=` controls the appended column name suffix; default is `_converted`.
148
+ - Same behaviour applies in `coordshift.html`: converted columns appear right after the originals in the downloaded CSV.
@@ -2,6 +2,7 @@ include README.md
2
2
  include LICENSE
3
3
  include CHANGELOG.md
4
4
  recursive-include docs *.md
5
+ recursive-include docs/images *.png
5
6
  recursive-include tests *.py *.csv
6
7
  prune venv
7
8
  prune dist
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coordshift
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Universal coordinate system conversion for CSV and tabular data
5
5
  Author: Nick Fulton
6
6
  License-Expression: MIT
@@ -45,7 +45,7 @@ Universal coordinate system conversion for CSV and tabular data — built for GI
45
45
  **CLI**
46
46
 
47
47
  ```bash
48
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat
48
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --x lon --y lat
49
49
  ```
50
50
 
51
51
  **Python**
@@ -53,7 +53,7 @@ coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat
53
53
  ```python
54
54
  from coordshift import convert
55
55
 
56
- df = convert("input.csv", from_crs="EPSG:4326", to_crs="EPSG:2965", x="lon", y="lat")
56
+ df = convert("input.csv", from_crs="EPSG:4326", to_crs="EPSG:6458", x="lon", y="lat")
57
57
  ```
58
58
 
59
59
  **Browser**
@@ -68,13 +68,15 @@ Tools like cs2cs, ogr2ogr, and raw pyproj are powerful but assume you already sp
68
68
 
69
69
  - Convert any EPSG/PROJ CRS to any other
70
70
  - Auto-detect common column names (lat, lon, x, y, easting, northing, etc.)
71
- - Source and target CRS via EPSG code, PROJ string, or friendly preset name
71
+ - Source and target CRS via EPSG code, PROJ string, or anything else PROJ resolves; `coordshift search` finds USA EPSG entries by keyword
72
72
  - Preserve all columns in output — original X/Y columns are always kept
73
73
  - Converted coordinates written to new columns placed immediately after the originals
74
74
  - Customisable output column suffix (default `_converted`, e.g. `lon_converted`, `lat_converted`)
75
75
  - CLI for one-off conversions
76
76
  - Python API for scripting and pipelines
77
- - Browser-based converter (`coordshift.html`) with map preview — works offline
77
+ - Browser-based converter (`coordshift.html`) with map preview — works offline, supports NAD83(2011)
78
+ geographic (EPSG:6318) for RTK/CORS survey workflows, with datum accuracy warnings for frames that
79
+ proj4.js cannot rigorously transform (e.g. NAD83(2011) ↔ ITRF2014)
78
80
 
79
81
  ## Planned
80
82
 
@@ -105,19 +107,19 @@ pip install -e .
105
107
  Basic conversion (original `lon`/`lat` columns are preserved; converted values go into `lon_converted`/`lat_converted` placed right after them):
106
108
 
107
109
  ```bash
108
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat
110
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --x lon --y lat
109
111
  ```
110
112
 
111
113
  With output path:
112
114
 
113
115
  ```bash
114
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat --out output.csv
116
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --x lon --y lat --out output.csv
115
117
  ```
116
118
 
117
119
  Custom column name suffix (produces `lon_proj`, `lat_proj` instead of the default `lon_converted`, `lat_converted`):
118
120
 
119
121
  ```bash
120
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --suffix _proj
122
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --suffix _proj
121
123
  ```
122
124
 
123
125
  PROJ strings (use a single line on Windows, or wrap as your shell allows):
@@ -129,13 +131,16 @@ coordshift convert input.csv \
129
131
  --x longitude --y latitude
130
132
  ```
131
133
 
132
- List presets and search CRS:
134
+ Search the EPSG database (filtered to USA) — one or more words, all must match:
133
135
 
134
136
  ```bash
135
- coordshift list-crs
136
- coordshift search "indiana east"
137
+ coordshift search iowa south
138
+ coordshift search indiana east
139
+ coordshift search nad83 2011 utm zone 15
137
140
  ```
138
141
 
142
+ The browser file `coordshift.html` includes a searchable CRS catalog for convenience. The Python tools rely on EPSG/PROJ plus `search` as above.
143
+
139
144
  ### Python API
140
145
 
141
146
  ```python
@@ -144,25 +149,51 @@ from coordshift import convert, search_crs
144
149
  df = convert(
145
150
  "field_points.csv",
146
151
  from_crs="EPSG:4326",
147
- to_crs="EPSG:2965",
152
+ to_crs="EPSG:6458",
148
153
  x="lon",
149
154
  y="lat",
150
155
  )
151
156
  # df now has lon, lon_converted, lat, lat_converted (plus any other original columns)
152
157
  df.to_csv("field_points_converted.csv", index=False)
153
158
 
159
+ # Search returns all matching EPSG entries from the PROJ database (USA-filtered)
154
160
  results = search_crs("indiana east")
161
+ for r in results:
162
+ print(r["epsg"], "—", r["name"])
155
163
  ```
156
164
 
157
165
  See [docs/examples.md](docs/examples.md) for more detailed examples.
158
166
 
159
167
  ### Browser app
160
168
 
161
- Open `coordshift.html` in any modern browser (Chrome, Firefox, Edge, Safari). No server or internet connection required after the page loads. Features include:
169
+ Open `coordshift.html` in any modern browser (Chrome, Firefox, Edge, Safari). No server or internet connection required after the page loads.
170
+
171
+ **How to use** — click **?** in the header to open the step-by-step guide:
172
+
173
+ ![coordshift browser app: How to use (instruction modal)](https://raw.githubusercontent.com/FultonGeo/coordshift/main/docs/images/coordshift_howto_html.png)
174
+
175
+ **Example** — map preview with input points (blue) and converted sample output (red); when the CRS pair is correct, the preview rings overlap the input dots:
176
+
177
+ ![coordshift browser app: sample conversion preview on the map](https://raw.githubusercontent.com/FultonGeo/coordshift/main/docs/images/coordshift_html_example.png)
178
+
179
+ Features include:
162
180
 
163
181
  - Upload a CSV and pick coordinate columns
164
- - Search and select source/target CRS from a built-in catalog of State Plane zones, UTM, and common geographic systems
165
- - Preview converted points on an interactive map
182
+ - Search and select source/target CRS from a built-in catalog that includes:
183
+ - **WGS 84** geographic (EPSG:4326) and Web Mercator (EPSG:3857)
184
+ - **NAD83(2011) geographic lat/lon (EPSG:6318)** — the reference frame reported by RTK GNSS
185
+ receivers observing from U.S. CORS networks; the correct source CRS for professional survey
186
+ fieldwork in the USA
187
+ - **ITRF2014** frame epoch 2010.0 (EPSG:9000)
188
+ - All **NAD83(2011) State Plane** zones for the contiguous U.S. and UTM zones
189
+ - **Map preview rings for all target CRS** — sample rings are back-projected to WGS 84 for
190
+ display, so rings land on the input points for projected output (State Plane, UTM) just as they
191
+ do for geographic output. Rings drift visibly if the wrong CRS is chosen.
192
+ - **Datum accuracy warnings** — an amber notice appears when the selected CRS pair has an offset
193
+ that proj4.js cannot model:
194
+ - *NAD83(2011) ↔ ITRF2014*: ~1 m (~4 ft) in CONUS due to tectonic plate drift since 1992
195
+ - *WGS 84 ↔ ITRF2014*: <2 cm (current WGS 84 G2139); directs users to EPSG:6318 for the
196
+ survey-grade NAD83 ↔ ITRF workflow
166
197
  - Download the converted CSV
167
198
 
168
199
  ## Project structure
@@ -174,15 +205,15 @@ coordshift/
174
205
  │ ├── core.py # Conversion (pyproj)
175
206
  │ ├── cli.py # CLI (Click)
176
207
  │ ├── io.py # CSV I/O, column detection
177
- ├── crs.py # CRS resolution
178
- │ └── presets.py # Friendly name → EPSG
208
+ └── crs.py # CRS resolution and EPSG search
179
209
  ├── tests/
180
210
  │ ├── test_core.py
181
211
  │ ├── test_cli.py
182
212
  │ ├── test_io.py
183
213
  │ └── fixtures/
184
214
  ├── docs/
185
- └── examples.md
215
+ ├── examples.md
216
+ │ └── images/ # README screenshots (browser app)
186
217
  ├── scripts/ # Developer tooling (regenerate HTML catalog)
187
218
  ├── coordshift.html # Standalone browser-based converter
188
219
  ├── pyproject.toml
@@ -15,7 +15,7 @@ Universal coordinate system conversion for CSV and tabular data — built for GI
15
15
  **CLI**
16
16
 
17
17
  ```bash
18
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat
18
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --x lon --y lat
19
19
  ```
20
20
 
21
21
  **Python**
@@ -23,7 +23,7 @@ coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat
23
23
  ```python
24
24
  from coordshift import convert
25
25
 
26
- df = convert("input.csv", from_crs="EPSG:4326", to_crs="EPSG:2965", x="lon", y="lat")
26
+ df = convert("input.csv", from_crs="EPSG:4326", to_crs="EPSG:6458", x="lon", y="lat")
27
27
  ```
28
28
 
29
29
  **Browser**
@@ -38,13 +38,15 @@ Tools like cs2cs, ogr2ogr, and raw pyproj are powerful but assume you already sp
38
38
 
39
39
  - Convert any EPSG/PROJ CRS to any other
40
40
  - Auto-detect common column names (lat, lon, x, y, easting, northing, etc.)
41
- - Source and target CRS via EPSG code, PROJ string, or friendly preset name
41
+ - Source and target CRS via EPSG code, PROJ string, or anything else PROJ resolves; `coordshift search` finds USA EPSG entries by keyword
42
42
  - Preserve all columns in output — original X/Y columns are always kept
43
43
  - Converted coordinates written to new columns placed immediately after the originals
44
44
  - Customisable output column suffix (default `_converted`, e.g. `lon_converted`, `lat_converted`)
45
45
  - CLI for one-off conversions
46
46
  - Python API for scripting and pipelines
47
- - Browser-based converter (`coordshift.html`) with map preview — works offline
47
+ - Browser-based converter (`coordshift.html`) with map preview — works offline, supports NAD83(2011)
48
+ geographic (EPSG:6318) for RTK/CORS survey workflows, with datum accuracy warnings for frames that
49
+ proj4.js cannot rigorously transform (e.g. NAD83(2011) ↔ ITRF2014)
48
50
 
49
51
  ## Planned
50
52
 
@@ -75,19 +77,19 @@ pip install -e .
75
77
  Basic conversion (original `lon`/`lat` columns are preserved; converted values go into `lon_converted`/`lat_converted` placed right after them):
76
78
 
77
79
  ```bash
78
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat
80
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --x lon --y lat
79
81
  ```
80
82
 
81
83
  With output path:
82
84
 
83
85
  ```bash
84
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --x lon --y lat --out output.csv
86
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --x lon --y lat --out output.csv
85
87
  ```
86
88
 
87
89
  Custom column name suffix (produces `lon_proj`, `lat_proj` instead of the default `lon_converted`, `lat_converted`):
88
90
 
89
91
  ```bash
90
- coordshift convert input.csv --from EPSG:4326 --to EPSG:2965 --suffix _proj
92
+ coordshift convert input.csv --from EPSG:4326 --to EPSG:6458 --suffix _proj
91
93
  ```
92
94
 
93
95
  PROJ strings (use a single line on Windows, or wrap as your shell allows):
@@ -99,13 +101,16 @@ coordshift convert input.csv \
99
101
  --x longitude --y latitude
100
102
  ```
101
103
 
102
- List presets and search CRS:
104
+ Search the EPSG database (filtered to USA) — one or more words, all must match:
103
105
 
104
106
  ```bash
105
- coordshift list-crs
106
- coordshift search "indiana east"
107
+ coordshift search iowa south
108
+ coordshift search indiana east
109
+ coordshift search nad83 2011 utm zone 15
107
110
  ```
108
111
 
112
+ The browser file `coordshift.html` includes a searchable CRS catalog for convenience. The Python tools rely on EPSG/PROJ plus `search` as above.
113
+
109
114
  ### Python API
110
115
 
111
116
  ```python
@@ -114,25 +119,51 @@ from coordshift import convert, search_crs
114
119
  df = convert(
115
120
  "field_points.csv",
116
121
  from_crs="EPSG:4326",
117
- to_crs="EPSG:2965",
122
+ to_crs="EPSG:6458",
118
123
  x="lon",
119
124
  y="lat",
120
125
  )
121
126
  # df now has lon, lon_converted, lat, lat_converted (plus any other original columns)
122
127
  df.to_csv("field_points_converted.csv", index=False)
123
128
 
129
+ # Search returns all matching EPSG entries from the PROJ database (USA-filtered)
124
130
  results = search_crs("indiana east")
131
+ for r in results:
132
+ print(r["epsg"], "—", r["name"])
125
133
  ```
126
134
 
127
135
  See [docs/examples.md](docs/examples.md) for more detailed examples.
128
136
 
129
137
  ### Browser app
130
138
 
131
- Open `coordshift.html` in any modern browser (Chrome, Firefox, Edge, Safari). No server or internet connection required after the page loads. Features include:
139
+ Open `coordshift.html` in any modern browser (Chrome, Firefox, Edge, Safari). No server or internet connection required after the page loads.
140
+
141
+ **How to use** — click **?** in the header to open the step-by-step guide:
142
+
143
+ ![coordshift browser app: How to use (instruction modal)](https://raw.githubusercontent.com/FultonGeo/coordshift/main/docs/images/coordshift_howto_html.png)
144
+
145
+ **Example** — map preview with input points (blue) and converted sample output (red); when the CRS pair is correct, the preview rings overlap the input dots:
146
+
147
+ ![coordshift browser app: sample conversion preview on the map](https://raw.githubusercontent.com/FultonGeo/coordshift/main/docs/images/coordshift_html_example.png)
148
+
149
+ Features include:
132
150
 
133
151
  - Upload a CSV and pick coordinate columns
134
- - Search and select source/target CRS from a built-in catalog of State Plane zones, UTM, and common geographic systems
135
- - Preview converted points on an interactive map
152
+ - Search and select source/target CRS from a built-in catalog that includes:
153
+ - **WGS 84** geographic (EPSG:4326) and Web Mercator (EPSG:3857)
154
+ - **NAD83(2011) geographic lat/lon (EPSG:6318)** — the reference frame reported by RTK GNSS
155
+ receivers observing from U.S. CORS networks; the correct source CRS for professional survey
156
+ fieldwork in the USA
157
+ - **ITRF2014** frame epoch 2010.0 (EPSG:9000)
158
+ - All **NAD83(2011) State Plane** zones for the contiguous U.S. and UTM zones
159
+ - **Map preview rings for all target CRS** — sample rings are back-projected to WGS 84 for
160
+ display, so rings land on the input points for projected output (State Plane, UTM) just as they
161
+ do for geographic output. Rings drift visibly if the wrong CRS is chosen.
162
+ - **Datum accuracy warnings** — an amber notice appears when the selected CRS pair has an offset
163
+ that proj4.js cannot model:
164
+ - *NAD83(2011) ↔ ITRF2014*: ~1 m (~4 ft) in CONUS due to tectonic plate drift since 1992
165
+ - *WGS 84 ↔ ITRF2014*: <2 cm (current WGS 84 G2139); directs users to EPSG:6318 for the
166
+ survey-grade NAD83 ↔ ITRF workflow
136
167
  - Download the converted CSV
137
168
 
138
169
  ## Project structure
@@ -144,15 +175,15 @@ coordshift/
144
175
  │ ├── core.py # Conversion (pyproj)
145
176
  │ ├── cli.py # CLI (Click)
146
177
  │ ├── io.py # CSV I/O, column detection
147
- ├── crs.py # CRS resolution
148
- │ └── presets.py # Friendly name → EPSG
178
+ └── crs.py # CRS resolution and EPSG search
149
179
  ├── tests/
150
180
  │ ├── test_core.py
151
181
  │ ├── test_cli.py
152
182
  │ ├── test_io.py
153
183
  │ └── fixtures/
154
184
  ├── docs/
155
- └── examples.md
185
+ ├── examples.md
186
+ │ └── images/ # README screenshots (browser app)
156
187
  ├── scripts/ # Developer tooling (regenerate HTML catalog)
157
188
  ├── coordshift.html # Standalone browser-based converter
158
189
  ├── pyproject.toml
@@ -9,5 +9,5 @@ Basic usage:
9
9
  from coordshift.core import convert
10
10
  from coordshift.crs import resolve_crs, search_crs
11
11
 
12
- __version__ = "0.1.1"
12
+ __version__ = "0.2.0"
13
13
  __all__ = ["convert", "resolve_crs", "search_crs"]
@@ -20,7 +20,6 @@ from pandas.errors import EmptyDataError, ParserError
20
20
  from coordshift import __version__
21
21
  from coordshift.core import convert as convert_file
22
22
  from coordshift.crs import CRSError, search_crs
23
- from coordshift.presets import PRESETS
24
23
 
25
24
 
26
25
  def _configure_utf8_stdio() -> None:
@@ -45,9 +44,6 @@ def _default_output_path(input_path: str) -> str:
45
44
  return str(p.with_name(f"{p.name}_converted"))
46
45
 
47
46
 
48
- def _format_preset_line(name: str, epsg: str, description: str) -> str:
49
- """Format one preset for terminal output."""
50
- return f"{name} → {epsg} — {description}"
51
47
 
52
48
 
53
49
  @click.group()
@@ -59,8 +55,8 @@ def cli():
59
55
 
60
56
  @cli.command()
61
57
  @click.argument("filepath", type=click.Path(exists=True))
62
- @click.option("--from", "from_crs", required=True, help="Source CRS (e.g. EPSG:4326, wgs84)")
63
- @click.option("--to", "to_crs", required=True, help="Target CRS (e.g. EPSG:2965, indiana-east)")
58
+ @click.option("--from", "from_crs", required=True, help="Source CRS (e.g. EPSG:4326 or PROJ string)")
59
+ @click.option("--to", "to_crs", required=True, help="Target CRS (e.g. EPSG:6458 or PROJ string)")
64
60
  @click.option("--x", default=None, help="X/longitude/easting column name (auto-detected if omitted)")
65
61
  @click.option("--y", default=None, help="Y/latitude/northing column name (auto-detected if omitted)")
66
62
  @click.option(
@@ -114,32 +110,21 @@ def convert(filepath, from_crs, to_crs, x, y, suffix, out):
114
110
 
115
111
 
116
112
  @cli.command()
117
- @click.argument("query")
118
- def search(query):
119
- """Search for a CRS by name or keyword. Example: coordshift search 'indiana'"""
120
- results = search_crs(query)
121
- if not results:
122
- click.echo(f"No presets found matching: {query}")
123
- return
124
- for row in sorted(results, key=lambda r: r["name"]):
125
- click.echo(
126
- _format_preset_line(
127
- row["name"],
128
- str(row["epsg"]),
129
- str(row["description"]),
130
- )
131
- )
113
+ @click.argument("query", nargs=-1, required=True)
114
+ def search(query: tuple[str, ...]) -> None:
115
+ """Search for a CRS by name or keyword.
132
116
 
117
+ Accepts one or more words — all words must match.
133
118
 
134
- @cli.command()
135
- def list_crs():
136
- """List all built-in CRS presets."""
137
- for name in sorted(PRESETS.keys()):
138
- data = PRESETS[name]
139
- click.echo(
140
- _format_preset_line(
141
- name,
142
- str(data["epsg"]),
143
- str(data.get("description", "")),
144
- )
145
- )
119
+ \b
120
+ Examples:
121
+ coordshift search iowa
122
+ coordshift search iowa south
123
+ coordshift search state plane north
124
+ """
125
+ results = search_crs(" ".join(query))
126
+ if not results:
127
+ click.echo(f"No results found for: {' '.join(query)}")
128
+ return
129
+ for row in results:
130
+ click.echo(f"{row['epsg']} — {row['name']}")
@@ -38,8 +38,8 @@ def transform_points(
38
38
  except PyprojCRSError as e:
39
39
  raise CRSError(
40
40
  f"Could not build coordinate transform from {from_crs!r} to {to_crs!r}: {e}. "
41
- "Use resolvable CRS strings or preset names. "
42
- "Run `coordshift search` to list presets."
41
+ "Use resolvable EPSG codes or PROJ strings. "
42
+ "Run `coordshift search` to find EPSG codes by name (USA-filtered)."
43
43
  ) from e
44
44
  tx, ty = transformer.transform(xs, ys)
45
45
  return [float(v) for v in tx], [float(v) for v in ty]
@@ -63,8 +63,8 @@ def convert(
63
63
 
64
64
  Args:
65
65
  filepath: Path to the input CSV file.
66
- from_crs: Source CRS — EPSG code (e.g. "EPSG:4326"), PROJ string, or preset name.
67
- to_crs: Target CRS — same formats accepted.
66
+ from_crs: Source CRS — EPSG code (e.g. "EPSG:4326"), PROJ string, or other form PROJ accepts.
67
+ to_crs: Target CRS — same formats as ``from_crs``.
68
68
  x: Name of the X/longitude/easting column. Auto-detected if not provided.
69
69
  y: Name of the Y/latitude/northing column. Auto-detected if not provided.
70
70
  output: Path to save the output CSV. If None, returns DataFrame only.