How to use the SNAP API from Python

This page provides an introduction to use the SNAP Java API from Python.

Introduction

SNAP implementation language is Java and therefore SNAP's "native" API is a Java API. According to the SNAP architecture, the reference SNAP Java API documentation of the two SNAP sub-systems SNAP Engine and SNAP Desktop nearly fully applies to use from Python as well.

It is possible to use the SNAP Java API from Python and there are basically two different ways to achieve this:

  1. Use an standard Python (CPython) installation

For either way, it is possible to call SNAP code from your Python programs/scripts and to extend SNAP by plugins written in Python. However, the two ways have pros and cons which should be considered before you make a decision which you want to follow.

Use the standard Python (CPython) approach, if

  • you require using the Python scientific extension libraries such as numpy, scipy, matplotlib, etc.;
  • you already have CPython code and you want to incorporate SNAP functions;
  • you plan to implement a fast data processor plugin in Python;
  • you do not plan to develop SNAP Desktop user interface extensions;
  • you do not require full portability on all platforms;
  • your code has (or will have) dependencies on a lot of non-standard libraries.

With the standard Python approach extension of SNAP is currently limited to raster data processor (Operator) plugins.

Use the Jython approach, if

  • you plan to develop SNAP Desktop user interface extensions;
  • you require full portability on all platforms;
  • do not require efficient array/raster data processing as provided by numpy and the like (because Jython does yet not well support these);.

Once you made your decision which approach to take, you can head to the dedicated section below.

This approach is explained on the Jython Approach page.

Standard Python (CPython) Approach

With this approach you can use a standard Python (CPython) interpreter installed on your computer (SNAP does not include a CPython interpreter.) The supported versions are Python 2.7, 3.3 to 3.6 64-bit (Linux + Darwin) and both 32-bit and 64-bit (Windows) as well as Anaconda distributions. 

The snappy Module

SNAP provides the Python module snappy which allows you to access the SNAP Java API from Python. snappy requires either a SNAP installation or a SNAP build.

Configuration

For how to configure Python for SNAP please see Configure Python to use the SNAP-Python (snappy) interface

Examples of SNAP API usage from Python

The following first example reads some raster data and displays/stores raster data as an RGB image:

Data IO 

Due to numerous writers implemented in the SNAP Engine reading and writing data in snappy is relatively simple. The general syntax is: 

Get and Set

It makes sense to start exploring the capabilities of snappy by reading a product (see above: snappy 1st Contact) and try out the methods and fields it contains. Calling get on an object in snappy (e.g. p.getRasterHeight()) returns either an Integer or String value or an object. Upon the latter, you can again normally call get again. This might again return an object with fields to return.
In the other direction, you may also set fields. For instance, if you called get and received a String value, you may set the same field of this object with a String.

Sometimes you might only be interested in “copying” a field from one object to another, let’s say from a source band to a target band. Then you may simply call get and set in one line without interacting with the return of get:

Often, snappy returns Integers (e.g. p.getSceneRasterWidth()) or Strings (e.g. p.getName()):

However, you might sometimes walk into Java objects that appear foreign to a Python user. These can e.g. be objects such as the return of:

In this case, you simply convert this to a Python list by calling:

In other cases, using str()converts a Java String to a Python String. For instance, you might be interested in the ‘autogrouping’ of the product. It defines how the bands are grouped in the product. The return of:

This can be easily converted to a Python String:

You may set the value by:


Processing in snappy

Snappy generally offers to ways how to process data:

Option A is suited when you aim at using only SNAP Engine Operators.

Option B is suited when you aim at doing custom computations for which you need to read data into Python numpy arrays.

Both options can, of course, occur in one workflow.

Option A: Process a product using a SNAP Engine Operator and write the target product

SNAP Operators are available in snappy via GPF.createProduct(). Its first parameter is a String denoting the name of the Operator as denoted in the Engine and available via GPT. If you have added GPT to your environment variables, you may call GPT from cmd in order to check out the available Operators, their description and parameters. In snappy, we provide the parameters through the second parameter of GPF.createProduct(). This parameter is a Java Hashmap, an object that is equivalent to a Python dictionary. The parameters must be named exactly with the String parameter name provided in GPT.

Instead of the NULL progress monitor, you can use a different monitor if you like to receive progress messages on the command line.


Option B: Process a product using custom data computations in Python

Using an implemented Operator might not be enough in cases where you aim to implement your own computation. The methods readPixels() and writePixels() help you to retrieve the necessary for the computation and save the result. We recommend to completely set up your target product in your script before computation starts. As in the examples above, p is still our source Product.

The target Product is ready for data to be written to it. Check out snappy examples on Github in order to know how to use readPixels() and writePixels() for reading data tiles, rows, columns or single pixels into numpy arrays and write them from output arrays into the respective band of the target Product. 


Further code examples

More example code of how to use the SNAP API in Python can be found in <snappy-dir>/examples. There is also a directory <snappy-dir>/testdata with a single EO test data product (*.dim) in it which you can pass as argument to the various examples. Please try

cd <snappy-dir>/examples
$ <python-exe> snappy_ndvi.py ../testdata/MER_FRS_L1B_SUBSET.dim

Note that the one and only reference for the SNAP Python API is the SNAP Java API documentation. All Java classes from the API can be "imported" by the jpy Java-Python bridge which is implicitely used by snappy. For example:
ProductIOPlugInManager = snappy.jpy.get_type('org.esa.snap.framework.dataio.ProductIOPlugInManager')
it = ProductIOPlugInManager.getInstance().getAllReaderPlugIns()
Also in the snap-examples repository are some more example snippets to find.

Python Operator Plugins

Python can be used extend SNAP by new raster data processor plugins, i.e. operators. Operators can be executed from the command-line, or invoked from the SNAP Desktop GUI, and be used as nodes in processing XML graphs. In the future, the SNAP development team will open more extension points for Python developers.

Example code for an operator plugin version of the snappy_ndvi.py example from above is provided on GitHub: https://github.com/senbox-org/snap-examples/tree/master/snap-engine-python-operator

How to Configure SNAP to pick up the build output automatically

Find the etc folder in the SNAP installation directory. Inside this directory you will find the snap.conf file. Change the access right of it so that you are allowed to make changes to it. There you will find the extra_clusters property. Specify the path, to the cluster folder of the build output directory.

Ensure to remove the '#' character at the beginning of the line.

Now when you start SNAP the build output is automatically used by SNAP and you can test the latest builds.