Goal
In this post we’ll try to get a better understanding of the structure of plpgsql ST_MapAlgebra
callback functions. Specifically, we’ll learn how to write a callback that works on one raster with one band.
Purpose
There are a few posts about how to do this. This one from George MacKerron’s blog gives a much better example of how MA callbacks work in PostGIS, and serves as a model of what I’ll attempt here. As Mr. MacKerron points out, the callback function in the documentation is pretty useless, but it’s also totally uninformative.
Basically, we’ll write a totally useless function which illustrates how we can manipulate raster values using ST_MapAlgebra
.
Getting Started
If you’re working with some real data, great! If you’re trying to learn more about ST_MapAlgebra
but don’t have a dataset, go check out my post on creating rasters from scratch.. This type of stuff is exactly what I had in mind when I wrote it.
One thing worth noting, is that there are two versions of ST_MapAlgebra
: the Expression Version and the Callback Version. Obviously, we’ll be working with the latter in this post. Both are great to be familiar with, but the Callback Version let’s us do much more complicated stuff, including working with cell neighbors (post coming soon). Here however, we’ll be doing a pretty basic operation. Still, it’s one that you couldn’t perform with the Expression Version (as far as I know, anyway)!
Using MacKerron’s post as a guide, I’ve laid out a basic structure that our callback has to follow.
We need three arguments:
- A 3 dimensional array of a type double precision
pixel double precision[][][]
- A 2 dimensional integer array
pos integer[][]
- A 1 dimensional variadic array to accept any additional user arguments
variadic userargs text[]
In our case, we’re working with integer data so we’ll plan our RETURNS
statement accordingly:
|
|
A note of caution:
I’ve seen several tutorials, including MacKerron’s and this one from Regina Obe, that use an array of a different type for the pixel value. I tried this, and it never worked for me with integer
. So, I’m sticking to double precision
here even though we’ll convert back to integer
at the end (as you can see from RETURNS integer
).
Let’s “Do Something”
We’ve initialized our raster with a value of 10 for all cells. As you can see from this picture, it’s pretty boring to look at. Let’s throw some chaos in there!
Since we are creating a random raster, but not entirely random. After all, it would be nice to learn a little bit about how to interact with our raster data since that’s the primary goal of this post. Bearing that in mind, let’s perform our operations using the values of our initial raster.
Let’s just get a random integer between 1 and 10 (inclusive) for each cell/pixel. We’ll multiply this by pixval
, our initial raster value.
|
|
Okay, so we run that, and we get FUNCTION CREATED
back. Time to test it out!
Here we’ll call the function on a dummy raster we saw above. We’ll take the result and stuff it in the empty table we created for the purpose.
|
|
Popping on over to QGIS, we can check out our results using the DBManager plugin. You can also use whatever tools you like, but I think those ones are great and they work very well together.
Wow, look at all that uniform noise! It seems like we achieved our objective. For a look at how to do write a callback that works with multiple bands, check out the next post in this series.