Using PCOT as a library

As well as being a stand-alone application, PCOT can be used as a library by other Python programs. This page discusses three ways to do this, although the various elements can be easily blended in a single program:

  • Loading a PCOT document, reading some data and passing it through the document's graph;
  • Building a PCOT document programmatically and passing data through it;
  • Using PCOT functions and data types without a graph.

While the latter two techniques can be useful for quick ad-hoc work, on the whole we feel it is better to exchange PCOT documents for traceability and clarity.

Loading and running PCOT documents

A typical example might be a script to read a PCOT document and run some data through that document's graph. You could do that like this:

# This example opens a graph, process some ENVI files through that graph,
# and saves them back to an ENVI. It assumes the graph has an "input 0" node
# which receives an image and a "sink" node which receives the processed
# image.

import pcot
from pcot.document import Document
from pcot.datum import Datum
from pcot.dataformats.envi import write

# initialise PCOT
pcot.setup()

# load the document
doc = Document("1.pcot")

# run the graph for some ENVI files. We'll just do one here, the ENVI
# document contained in the files 1.hdr and 1.dat (an ENVI document
# consists of two files: header and data).

for file in ("1",):

    # load the given ENVI file into input 0
    rv = doc.setInputENVI(0, file+".hdr")
    if rv is not None:
        raise Exception(f"{rv}")

    # run the document's graph 
    doc.run()

    # get the "sink" node
    outNode = doc.getNodeByName("sink")

    # get its output
    img = outNode.out.get(Datum.IMG)

    # write to new ENVI, e.g. 1b.hdr
    write(file+"b",img)

Building a PCOT document

It's also possible to build a PCOT document, creating nodes within its graph. Consider the graph

A simple graph
Figure: A simple graph. Click on image to expand.

This could be built and run for a particular file with the following code:

#!/usr/bin/env python

import pcot
import pcot.document
from pcot.datum import Datum

pcot.setup()

doc = pcot.document.Document()

result = doc.setInputENVI(0, "/home/white/PCOT/fff.hdr") is not None
assert result is not None

# create a document with just an input node in it, to bring that input into the document's graph
innode = doc.graph.create("input 0")

# add a region of interest (ROI) node to the image
roinode = doc.graph.create("circle")
# set the circle to be centred at (32,32) with a radius of 3 pixels
roinode.roi.set(32,32,3)

# connect its first input to the input node's first output
# args: 
#   input on this node to connect
#   node to get connection from
#   index on that node to connect to.
roinode.connect(0,innode,0)     

# connect a node to the ROI node which takes the resulting image-with-ROI
# and plots the spectrum of that ROI

specnode = doc.graph.create("spectrum")
specnode.connect(0,roinode,0)

# run the document
doc.run()

# get the output of the spectrum node, which will be a Datum,
# and dereference the Datum, ensuring that the data is of the right type.
# The result will be a Table object.
output = specnode.getOutput(0, Datum.DATA)

# print the table as CSV.
print(output)

Using PCOT functions and data types without a graph

Often it is much simpler to just use the underlying PCOT data types without a graph. The operation described in the previous section is an example of this. We could use the dataformats.load package to load the data directly and manipulate it:

#!/usr/bin/env python

import pcot
from pcot.datum import Datum
from pcot.dataformats import load
from pcot.rois import ROICircle
from pcot.utils.spectrum import SpectrumSet

pcot.setup()

# load the ENVI file as a Datum object. Will raise an exception
# if there is a problem
datum = load.envi("/home/white/PCOT/fff.hdr")

# retrieve the image, ensuring it's an IMG datum
img = datum.get(Datum.IMG)

# add a region of interest (ROI) node to the image:
# a circle to be centred at (32,32) with a radius of 3 pixels
img.rois.append(ROICircle(32,32,3))

# construct a spectrum set from this image - this can create spectra
# for multiple sources and combine them. Here we are just using a single
# source - the image we are working with - and we're calling it "in."
ss = SpectrumSet({"in": img})

# Generate a table from the results and print it (as a CSV table).
print(ss.table())