22"""
33Generate layers-config.json from STAC catalog entries.
44
5- This script reads STAC collections and generates layer configurations
6- for the CA Protected Lands maplibre application.
5+ This script reads a JSON input file specifying STAC collections and assets,
6+ then generates layer configurations for the CA Protected Lands maplibre application.
77
88Usage:
9- python stac-to-layers-config.py --catalog CATALOG_URL --output layers-config.json \
10- --layer collection_id:asset_id:layer_key:display_name
9+ python3 stac-to-layers-config.py --input layers-input.json --output layers-config.json
1110
12- Examples:
13- # Generate config for CPAD and carbon layers
14- python stac-to-layers-config.py \
15- --catalog https://s3-west.nrp-nautilus.io/public-data/stac/catalog.json \
16- --output app/layers-config.json \
17- --layer cpad-2025b:cpad-units-pmtiles:cpad:"California Protected Areas (CPAD)" \
18- --layer irrecoverable-carbon:vulnerable-total-2018-cog:carbon:"Vulnerable Carbon"
11+ Example:
12+ python3 stac-to-layers-config.py \
13+ --input scripts/layers-input-example.json \
14+ --output app/layers-config.json
1915"""
2016
2117import argparse
@@ -202,89 +198,39 @@ def main():
202198 formatter_class = argparse .RawDescriptionHelpFormatter ,
203199 epilog = __doc__
204200 )
205-
206- # Input method 1: JSON file
207201 parser .add_argument (
208202 "--input" ,
209- help = "Path to input JSON file specifying layers (recommended)"
210- )
211-
212- # Input method 2: Command line arguments (legacy)
213- parser .add_argument (
214- "--catalog" ,
215- help = "URL to STAC catalog.json (required if not using --input)"
203+ required = True ,
204+ help = "Path to input JSON file specifying layers"
216205 )
217206 parser .add_argument (
218207 "--output" ,
219208 required = True ,
220209 help = "Output path for layers-config.json"
221210 )
222- parser .add_argument (
223- "--layer" ,
224- action = "append" ,
225- metavar = "COLLECTION:ASSET:KEY:NAME" ,
226- help = "Layer specification: collection_id:asset_id:layer_key:display_name (can be specified multiple times)"
227- )
228- parser .add_argument (
229- "--titiler" ,
230- default = "https://titiler.nrp-nautilus.io" ,
231- help = "TiTiler base URL for COG tiles (default: https://titiler.nrp-nautilus.io)"
232- )
233- parser .add_argument (
234- "--colormap" ,
235- default = "reds" ,
236- help = "Default colormap for raster layers (default: reds)"
237- )
238211
239212 args = parser .parse_args ()
240213
241- # Determine input method
242- if args .input :
243- # Load from JSON file
244- input_path = Path (args .input )
245- if not input_path .exists ():
246- print (f"Error: Input file '{ args .input } ' not found" , file = sys .stderr )
247- sys .exit (1 )
248-
249- with open (input_path ) as f :
250- input_config = json .load (f )
251-
252- catalog_url = input_config .get ("catalog" )
253- if not catalog_url :
254- print ("Error: 'catalog' field required in input JSON" , file = sys .stderr )
255- sys .exit (1 )
256-
257- titiler_url = input_config .get ("titiler_url" , args .titiler )
258- layer_specs = input_config .get ("layers" , [])
259-
260- if not layer_specs :
261- print ("Error: 'layers' array is empty in input JSON" , file = sys .stderr )
262- sys .exit (1 )
214+ # Load JSON input file
215+ input_path = Path (args .input )
216+ if not input_path .exists ():
217+ print (f"Error: Input file '{ args .input } ' not found" , file = sys .stderr )
218+ sys .exit (1 )
263219
264- elif args .catalog and args .layer :
265- # Use command-line arguments (legacy mode)
266- catalog_url = args .catalog
267- titiler_url = args .titiler
268- layer_specs = []
269-
270- for layer_spec in args .layer :
271- parts = layer_spec .split (":" , 3 )
272- if len (parts ) < 3 :
273- print (f"Error: Invalid layer specification '{ layer_spec } '" , file = sys .stderr )
274- print ("Format: collection_id:asset_id:layer_key[:display_name]" , file = sys .stderr )
275- sys .exit (1 )
276-
277- layer_specs .append ({
278- "collection_id" : parts [0 ],
279- "asset_id" : parts [1 ],
280- "layer_key" : parts [2 ],
281- "display_name" : parts [3 ] if len (parts ) > 3 else None ,
282- "options" : {}
283- })
220+ with open (input_path ) as f :
221+ input_config = json .load (f )
284222
285- else :
286- print ("Error: Must specify either --input or both --catalog and --layer" , file = sys .stderr )
287- parser .print_help ()
223+ catalog_url = input_config .get ("catalog" )
224+ if not catalog_url :
225+ print ("Error: 'catalog' field required in input JSON" , file = sys .stderr )
226+ sys .exit (1 )
227+
228+ titiler_url = input_config .get ("titiler_url" , "https://titiler.nrp-nautilus.io" )
229+ default_colormap = input_config .get ("default_colormap" , "reds" )
230+ layer_specs = input_config .get ("layers" , [])
231+
232+ if not layer_specs :
233+ print ("Error: 'layers' array is empty in input JSON" , file = sys .stderr )
288234 sys .exit (1 )
289235
290236 # Generate layers configuration
@@ -301,6 +247,10 @@ def main():
301247 display_name = spec .get ("display_name" )
302248 options = spec .get ("options" , {})
303249
250+ if not all ([collection_id , asset_id , layer_key ]):
251+ print (f"Error: Layer spec missing required fields: { spec } " , file = sys .stderr )
252+ sys .exit (1 )
253+
304254 print (f"Processing { collection_id } :{ asset_id } -> { layer_key } ..." , file = sys .stderr )
305255
306256 # Find collection URL
@@ -313,7 +263,7 @@ def main():
313263 collection = fetch_json (collection_url )
314264
315265 # Get options with defaults
316- colormap = options .get ("colormap" , args . colormap )
266+ colormap = options .get ("colormap" , default_colormap )
317267 rescale = options .get ("rescale" )
318268
319269 # Generate layer config
0 commit comments