transformez 0.3.2__tar.gz → 0.3.4__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.
Files changed (24) hide show
  1. {transformez-0.3.2 → transformez-0.3.4}/CHANGELOG.md +9 -1
  2. {transformez-0.3.2 → transformez-0.3.4}/PKG-INFO +1 -1
  3. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/__init__.py +4 -0
  4. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/_version.py +1 -1
  5. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/api.py +32 -25
  6. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/cli.py +54 -21
  7. transformez-0.3.4/src/transformez/definitions.py +499 -0
  8. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/grid_engine.py +64 -27
  9. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/hooks.py +20 -10
  10. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/htdp.py +27 -29
  11. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/modules.py +30 -15
  12. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/spatial.py +53 -30
  13. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/srs.py +67 -57
  14. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/transform.py +198 -84
  15. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/utils.py +6 -7
  16. {transformez-0.3.2 → transformez-0.3.4}/src/transformez/vdatum.py +27 -13
  17. transformez-0.3.2/src/transformez/definitions.py +0 -256
  18. {transformez-0.3.2 → transformez-0.3.4}/AUTHORS.md +0 -0
  19. {transformez-0.3.2 → transformez-0.3.4}/CITATION.cff +0 -0
  20. {transformez-0.3.2 → transformez-0.3.4}/CONTRIBUTING.md +0 -0
  21. {transformez-0.3.2 → transformez-0.3.4}/LICENSE +0 -0
  22. {transformez-0.3.2 → transformez-0.3.4}/README.md +0 -0
  23. {transformez-0.3.2 → transformez-0.3.4}/pyproject.toml +0 -0
  24. {transformez-0.3.2 → transformez-0.3.4}/tests/test_cli.py +0 -0
@@ -5,7 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [ Unreleased]
8
+ ## [unreleased]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ## [0.3.2] - 2026-05-27
9
15
 
10
16
  ### Added
11
17
  - support for FES2014
@@ -16,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
22
  ### Changed
17
23
  - cli now uses click
18
24
 
25
+ <...missed...>
26
+
19
27
  ## [0.1.0] - 2026-02-10
20
28
  ### Added
21
29
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: transformez
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: A standalone utility for vertical elevation datum transformations.
5
5
  Project-URL: Homepage, https://github.com/continuous-dems/transformez
6
6
  Project-URL: Issues, https://github.com/continuous-dems/transformez/issues
@@ -33,11 +33,13 @@ import glob
33
33
  # Expose the module for fetchez
34
34
  from .modules import TransformezMod
35
35
 
36
+
36
37
  def _find_proj_lib():
37
38
  """Locate the best available PROJ_LIB path."""
38
39
 
39
40
  try:
40
41
  import rasterio
42
+
41
43
  r_path = os.path.join(os.path.dirname(rasterio.__file__), "proj_data")
42
44
  if os.path.exists(os.path.join(r_path, "proj.db")):
43
45
  return r_path
@@ -53,6 +55,7 @@ def _find_proj_lib():
53
55
 
54
56
  try:
55
57
  import pyproj
58
+
56
59
  p_path = pyproj.datadir.get_data_dir()
57
60
  if os.path.exists(os.path.join(p_path, "proj.db")):
58
61
  return p_path
@@ -61,6 +64,7 @@ def _find_proj_lib():
61
64
 
62
65
  return None
63
66
 
67
+
64
68
  target_proj_lib = _find_proj_lib()
65
69
 
66
70
  if "PROJ_LIB" in os.environ:
@@ -1,4 +1,4 @@
1
1
  # This file is auto-generated by Hatchling. As such, do not:
2
2
  # - modify
3
3
  # - track in version control e.g. be sure to add to .gitignore
4
- __version__ = VERSION = '0.3.2'
4
+ __version__ = VERSION = '0.3.4'
@@ -46,12 +46,10 @@ def _parse_datum(datum_arg: str) -> Tuple[Optional[int], Optional[str]]:
46
46
  if not datum_arg:
47
47
  return None, None
48
48
  s = str(datum_arg)
49
- if ':' in s:
50
- parts = s.split(':')
49
+ if ":" in s:
50
+ parts = s.split(":")
51
51
  geoid_part = parts[1]
52
- geoid = (
53
- geoid_part.split('=')[1] if 'geoid=' in geoid_part else geoid_part
54
- )
52
+ geoid = geoid_part.split("=")[1] if "geoid=" in geoid_part else geoid_part
55
53
  return Datums.get_vdatum_by_name(parts[0]), geoid
56
54
  return Datums.get_vdatum_by_name(s), None
57
55
 
@@ -75,8 +73,7 @@ def plot_grid(grid_array, region, title="Vertical Shift Preview"):
75
73
  region_obj = regions[0]
76
74
 
77
75
  masked_data = np.ma.masked_where(
78
- (np.isnan(grid_array)) | (grid_array == -9999) | (grid_array == 0),
79
- grid_array
76
+ (np.isnan(grid_array)) | (grid_array == -9999) | (grid_array == 0), grid_array
80
77
  )
81
78
 
82
79
  if masked_data.count() == 0:
@@ -93,13 +90,19 @@ def plot_grid(grid_array, region, title="Vertical Shift Preview"):
93
90
  plt.title(title)
94
91
  plt.xlabel("Longitude")
95
92
  plt.ylabel("Latitude")
96
- plt.grid(True, linestyle=':', alpha=0.6)
93
+ plt.grid(True, linestyle=":", alpha=0.6)
97
94
 
98
- stats = (f"Min: {masked_data.min():.3f} m\n"
99
- f"Max: {masked_data.max():.3f} m\n"
100
- f"Mean: {masked_data.mean():.3f} m")
101
- plt.annotate(stats, xy=(0.02, 0.02), xycoords='axes fraction',
102
- bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="gray", alpha=0.8))
95
+ stats = (
96
+ f"Min: {masked_data.min():.3f} m\n"
97
+ f"Max: {masked_data.max():.3f} m\n"
98
+ f"Mean: {masked_data.mean():.3f} m"
99
+ )
100
+ plt.annotate(
101
+ stats,
102
+ xy=(0.02, 0.02),
103
+ xycoords="axes fraction",
104
+ bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="gray", alpha=0.8),
105
+ )
103
106
  logger.info("Displaying preview... Close the plot window to continue.")
104
107
  plt.show()
105
108
 
@@ -156,12 +159,15 @@ def generate_grid(
156
159
 
157
160
  vt = VerticalTransform(
158
161
  region=region_obj,
159
- nx=nx, ny=ny,
160
- epsg_in=epsg_in, epsg_out=epsg_out,
161
- geoid_in=geoid_in, geoid_out=geoid_out,
162
+ nx=nx,
163
+ ny=ny,
164
+ epsg_in=epsg_in,
165
+ epsg_out=epsg_out,
166
+ geoid_in=geoid_in,
167
+ geoid_out=geoid_out,
162
168
  decay_pixels=decay_pixels,
163
169
  cache_dir=cache_dir,
164
- verbose=verbose
170
+ verbose=verbose,
165
171
  )
166
172
 
167
173
  shift_array, _ = vt._vertical_transform(vt.epsg_in, vt.epsg_out)
@@ -184,7 +190,7 @@ def transform_raster(
184
190
  decay_pixels: int = 100,
185
191
  output_raster: Optional[str] = None,
186
192
  cache_dir: Optional[str] = None,
187
- verbose: bool = False
193
+ verbose: bool = False,
188
194
  ) -> Optional[str]:
189
195
  """Apply a vertical datum transformation directly to an existing raster file.
190
196
 
@@ -209,9 +215,7 @@ def transform_raster(
209
215
 
210
216
  with rasterio.open(input_raster) as src:
211
217
  bounds = src.bounds
212
- region_obj = (
213
- Region(bounds.left, bounds.right, bounds.bottom, bounds.top)
214
- )
218
+ region_obj = Region(bounds.left, bounds.right, bounds.bottom, bounds.top)
215
219
  nx, ny = src.width, src.height
216
220
 
217
221
  epsg_in, geoid_in = _parse_datum(datum_in)
@@ -227,12 +231,15 @@ def transform_raster(
227
231
 
228
232
  vt = VerticalTransform(
229
233
  region=region_obj,
230
- nx=nx, ny=ny,
231
- epsg_in=epsg_in, epsg_out=epsg_out,
232
- geoid_in=geoid_in, geoid_out=geoid_out,
234
+ nx=nx,
235
+ ny=ny,
236
+ epsg_in=epsg_in,
237
+ epsg_out=epsg_out,
238
+ geoid_in=geoid_in,
239
+ geoid_out=geoid_out,
233
240
  decay_pixels=decay_pixels,
234
241
  cache_dir=cache_dir,
235
- verbose=verbose
242
+ verbose=verbose,
236
243
  )
237
244
 
238
245
  shift_array, _ = vt._vertical_transform(vt.epsg_in, vt.epsg_out)
@@ -15,29 +15,47 @@ import sys
15
15
  import click
16
16
  import logging
17
17
  from transformez import api
18
- from transformez import grid_engine
19
18
 
20
- logger = logging.getLogger(__name__)
19
+ # logger = logging.getLogger(__name__)
21
20
 
22
21
 
23
22
  @click.group(name="transform")
24
- @click.version_option(package_name='transformez')
23
+ @click.version_option(package_name="transformez")
25
24
  def transformez_cli():
26
25
  """Apply vertical datum transformations and generate shift grids."""
27
26
 
27
+ logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(message)s')
28
28
  pass
29
29
 
30
30
 
31
31
  @transformez_cli.command("run")
32
32
  @click.argument("input_file", required=False)
33
- @click.option("-R", "--region", help="Bounding box or location string (if no input file).")
34
- @click.option("-E", "--increment", help="Resolution (e.g., 1s, 30m) (if no input file).")
35
- @click.option("-I", "--input-datum", required=True, help="Source Datum (e.g., 'mllw', '5703').")
36
- @click.option("-O", "--output-datum", required=True, help="Target Datum (e.g., '4979', '5703:g2012b').")
33
+ @click.option(
34
+ "-R", "--region", help="Bounding box or location string (if no input file)."
35
+ )
36
+ @click.option(
37
+ "-E", "--increment", help="Resolution (e.g., 1s, 30m) (if no input file)."
38
+ )
39
+ @click.option(
40
+ "-I", "--input-datum", required=True, help="Source Datum (e.g., 'mllw', '5703')."
41
+ )
42
+ @click.option(
43
+ "-O",
44
+ "--output-datum",
45
+ required=True,
46
+ help="Target Datum (e.g., '4979', '5703:g2012b').",
47
+ )
37
48
  @click.option("--out", "-o", help="Output filename (default: auto-named).")
38
- @click.option("--decay-pixels", type=int, default=100, help="Number of pixels to decay tidal shifts inland.")
49
+ @click.option(
50
+ "--decay-pixels",
51
+ type=int,
52
+ default=100,
53
+ help="Number of pixels to decay tidal shifts inland.",
54
+ )
39
55
  @click.option("--preview", is_flag=True, help="Preview the transformation output.")
40
- def transform_run(input_file, region, increment, input_datum, output_datum, out, decay_pixels, preview):
56
+ def transform_run(
57
+ input_file, region, increment, input_datum, output_datum, out, decay_pixels, preview
58
+ ):
41
59
  """Transform a raster's vertical datum or generate a standalone shift grid.
42
60
 
43
61
  If an INPUT_FILE is provided, that specific raster is transformed in place.
@@ -58,17 +76,23 @@ def transform_run(input_file, region, increment, input_datum, output_datum, out,
58
76
  datum_out=output_datum,
59
77
  decay_pixels=decay_pixels,
60
78
  output_raster=out,
61
- verbose=True
79
+ verbose=True,
62
80
  )
63
81
 
64
82
  if result:
65
- click.secho(f"Successfully transformed raster: {result}", fg="green", bold=True)
83
+ click.secho(
84
+ f"Successfully transformed raster: {result}", fg="green", bold=True
85
+ )
66
86
  else:
67
87
  click.secho("Failed to transform raster.", fg="red")
68
88
  sys.exit(1)
69
89
 
70
90
  elif region and increment:
71
- click.secho(f"Generating vertical shift grid for region: {region}...", fg="cyan", bold=True)
91
+ click.secho(
92
+ f"Generating vertical shift grid for region: {region}...",
93
+ fg="cyan",
94
+ bold=True,
95
+ )
72
96
  click.echo(f" Shift: {input_datum} ➔ {output_datum} @ {increment}")
73
97
 
74
98
  # Auto-generate an output name if one wasn't provided
@@ -81,20 +105,25 @@ def transform_run(input_file, region, increment, input_datum, output_datum, out,
81
105
  datum_out=output_datum,
82
106
  decay_pixels=decay_pixels,
83
107
  out_fn=out_fn,
84
- verbose=True
108
+ verbose=True,
85
109
  )
86
110
 
87
111
  if preview:
88
112
  api.plot_grid(result, region)
89
113
 
90
114
  if result is not None:
91
- click.secho(f"Successfully generated shift grid: {out_fn}", fg="green", bold=True)
115
+ click.secho(
116
+ f"Successfully generated shift grid: {out_fn}", fg="green", bold=True
117
+ )
92
118
  else:
93
119
  click.secho("Failed to generate shift grid.", fg="red")
94
120
  sys.exit(1)
95
121
 
96
122
  else:
97
- click.secho("Error: You must provide either an INPUT_FILE or both --region and --increment.", fg="red")
123
+ click.secho(
124
+ "Error: You must provide either an INPUT_FILE or both --region and --increment.",
125
+ fg="red",
126
+ )
98
127
  sys.exit(1)
99
128
 
100
129
 
@@ -107,7 +136,7 @@ def transform_list():
107
136
  click.secho("\n🌊 Supported Tidal Surfaces:", fg="cyan", bold=True)
108
137
  # For tidal datums, the user types the dictionary key (e.g., 'mllw')
109
138
  for key, v in Datums.SURFACES.items():
110
- region_str = v.get('region', 'global').upper()
139
+ region_str = v.get("region", "global").upper()
111
140
  click.echo(f" {key:<12} : {v.get('name', key):<30} [{region_str}]")
112
141
 
113
142
  click.secho("\n🌐 Ellipsoidal / Frame Datums (EPSG):", fg="cyan", bold=True)
@@ -119,19 +148,23 @@ def transform_list():
119
148
  # For orthometric, the key in Datums.CDN is typically the EPSG code (e.g., '5703')
120
149
  for epsg_key, v in Datums.CDN.items():
121
150
  # Fallback to the key if 'epsg' isn't explicitly defined in the dict
122
- epsg_code = v.get('epsg', epsg_key)
123
- geoid_str = v.get('default_geoid', 'None')
124
- click.echo(f" {str(epsg_code):<12} : {v.get('name', 'Unknown'):<30} (Default Geoid: {geoid_str})")
151
+ epsg_code = v.get("epsg", epsg_key)
152
+ geoid_str = v.get("default_geoid", "None")
153
+ click.echo(
154
+ f" {str(epsg_code):<12} : {v.get('name', 'Unknown'):<30} (Default Geoid: {geoid_str})"
155
+ )
125
156
 
126
157
  click.secho("\n🌍 Available Geoids:", fg="cyan", bold=True)
127
158
  click.echo(f" {', '.join(Datums.GEOIDS.keys())}")
128
159
 
129
160
  click.secho("\n💡 Pro-Tip:", fg="yellow", bold=True, nl=False)
130
- click.echo(" Combine an EPSG and a specific Geoid using a colon (e.g., -O 5703:g2012b)\n")
161
+ click.echo(
162
+ " Combine an EPSG and a specific Geoid using a colon (e.g., -O 5703:g2012b)\n"
163
+ )
131
164
 
132
165
  except ImportError:
133
166
  click.secho("Error: Could not load Transformez datum definitions.", fg="red")
134
167
 
135
168
 
136
- if __name__ == '__main__':
169
+ if __name__ == "__main__":
137
170
  transformez_cli()