Scripting with GeoIPS plugins#

GeoIPS plugins can be called directly from Python using the same DataTree-based data model that Order-Based Processing uses internally. This is the recommended way to explore data interactively, prototype new processing, and drive GeoIPS from notebooks.

In this mode your script owns a top-level xarray.DataTree and passes it from plugin to plugin. Each plugin reads the inputs it understands from the tree, writes its result back under a named step, applies the requested retention policy, and returns the updated tree.

Note

The public scripting API lives in geoips.scripting. Prefer importing from there; lower level helpers may move.

Initialize a script tree#

Start every script by initializing a tree with a GeoIPS helper (not a bare xarray.DataTree):

from geoips.scripting import RetentionPolicy, initialize_script_tree

tree = initialize_script_tree(
    name="abi_infrared_test",
    retention_policy=RetentionPolicy.metadata_only,
)

The initializer validates the retention policy and stamps script-level metadata (execution_mode="script", start_time, etc.). GeoIPS manages start_time/end_time — do not pass them yourself. Because the tree records execution_mode="script", normal script calls do not need _obp_initiated=True.

Call plugins#

Resolve plugins from their interfaces and call them, passing the accumulated tree as data and naming each result with step_id:

from geoips.interfaces import readers, interpolators, algorithms

reader = readers.get_plugin("abi_netcdf")
tree = reader(data=tree, filenames=fnames, step_id="read_data", variables=["B14BT"])

interpolator = interpolators.get_plugin("interp_nearest")
tree = interpolator(data=tree, step_id="interpolate_data", varlist=["B14BT"])

algorithm = algorithms.get_plugin("single_channel")
tree = algorithm(
    data=tree,
    step_id="apply_algorithm",
    output_data_range=[-90.0, 30.0],
    input_units="Kelvin",
    output_units="celsius",
)

Some YAML-based plugins (e.g. sectors) do not yet route through class-based script invocation. Attach their results explicitly:

from geoips.interfaces import sectors
from geoips.scripting import attach_plugin_result

sector = sectors.get_plugin("conus")
tree = attach_plugin_result(
    tree, sector(), step_id="load_sector", plugin_kind="sector", plugin_name="conus"
)

Inspect and modify data between steps#

get_current_data() returns a mutable copy of the most recent data-containing step. Edit it and reinsert it as a new manual step with add_data_step():

from geoips.scripting import add_data_step, get_current_data

xobj = get_current_data(tree)
xobj["data"] = xobj["data"].where(xobj["data"] > -80)
tree = add_data_step(tree, xobj, step_id="mask_cold_pixels")

Get outputs#

After an output formatter step, collect the written products:

from geoips.scripting import get_output_products

output_products = get_output_products(tree, step_id="write_image")
print(output_products)

Step names#

step_id names each result in the tree — it is the scripting equivalent of a workflow step id. Use active, descriptive names (read_data, interpolate_data, apply_algorithm, write_image). If omitted, GeoIPS uses the plugin name and errors if that would collide with an existing node.

Input discovery and conflicts#

When you call a plugin with an accumulated tree, GeoIPS inspects the tree’s child nodes and extracts the inputs meaningful to that plugin; unrelated nodes are ignored. If multiple nodes can supply the same input, the most recent matching node wins (by insertion order). Explicit keyword arguments always take precedence over values found in the tree.

Bring your own data#

Scripts can start from data a GeoIPS reader did not produce. Provide it as an xarray object and insert it with add_data_step(); downstream plugins still expect the standard GeoIPS variables, coordinates, and metadata attributes.

import xarray as xr
from geoips.scripting import add_data_step, initialize_script_tree, RetentionPolicy

tree = initialize_script_tree(name="byo", retention_policy=RetentionPolicy.metadata_only)
xobj = xr.Dataset(
    data_vars={"my_variable": (("y", "x"), data_values)},
    coords={"latitude": (("y", "x"), lat), "longitude": (("y", "x"), lon)},
    attrs={"source_name": "my_source", "platform_name": "my_platform",
           "start_datetime": start, "end_datetime": end},
)
tree = add_data_step(tree, xobj, step_id="load_external_data")

See also#