HOWTO pin one CRS for a whole session
Planetary work spans archives, and archives disagree about coordinate reference systems. A USGS gazetteer shapefile arrives as ESRI:104905, a HiRISE product carries an IAU_2015 code, ESA PSA hands you bare degrees. Restating the frame you want at every call is tedious, and forgetting once is how two datasets end up silently in different systems.
Set it once instead.
from planetarypy import crs
crs.set_target_crs("IAU_2015:49900") # Mars, ocentricFrom here on, helpers that return georeferenced data convert to that frame rather than handing back whatever their upstream source happened to use.
Just for a block
crs.target_crs is the context-manager form. Use it when one section of an analysis needs a different frame — a local projection for a distance calculation, say — without disturbing the session setting.
local = crs.local_crs(77.4, 18.4, "mars") # azeqd centred on Jezero
with crs.target_crs(local):
... # metres, centred on Jezero
# the previous setting is back here, even if the block raisedIt nests, and it restores on exception. Passing None suspends the session setting for the block:
with crs.target_crs(None):
... # no automatic conversion at allWho wins
Three things can name a CRS, so the order is fixed and lives in one function:
crs.resolve_crs(explicit, fallback=crs.body_crs("mars"))explicit— what the caller passed to this specific call.- the session target —
set_target_crs, or the enclosingtarget_crsblock. fallback— usually the body’s own IAU CRS.
If all three are None, resolve_crs returns None, which callers read as “leave the data alone”.
You are told when it happens
A conversion you did not ask for announces itself:
CRSConversionWarning: mars nomenclature reprojected from ESRI:104905 to
IAU_2015:49900 automatically. Pass an explicit CRS, or set
planetarypy.crs.set_target_crs(...), to choose deliberately.
Both authorities are named, because that is the information you need to judge whether the conversion was the one you wanted. ESRI:104905 and IAU_2015:49900 differ in more than their label.
The notice is a warning rather than a log line on purpose: planetarypy disables its logger by default for library use, so a log message here would be invisible to exactly the people who need to see it.
Conversions you did ask for — by passing an explicit CRS — stay quiet. You already made the decision.
Silencing it
It has its own category, so you can turn it off without muting anything else:
import warnings
from planetarypy.crs import CRSConversionWarning
warnings.filterwarnings("ignore", category=CRSConversionWarning)Threads and async
The setting is held in a contextvars.ContextVar, not a module global. A worker thread does not inherit the main thread’s target CRS, and concurrent tasks cannot overwrite each other’s. If you want a thread to share the setting, set it inside that thread.
Clearing up
crs.clear_target_crs() # forget it
crs.get_target_crs() # -> Noneset_target_crs also returns the previous value, if you would rather restore it by hand than use the context manager:
previous = crs.set_target_crs("IAU_2015:49901")
...
crs.set_target_crs(previous)