Question

unpacking python array into FME attributes


Userlevel 4
Badge +25

Hey folks. Just working on a project of my own (inspired by this and similar questions) and am using some Python code I found online.

Basically it creates an array (vstack) like so:

[[ 0  3  4  5]
 [ 1  2  7  6]
 [14 13  8  9]
 [15 12 11 10]]

What I'm wondering is if anyone has some hints on how to extract these into FME attributes? You might notice that by following the numbers you get what is apparently called a Hilbert Curve. I'm trying to plot that path as a feature in FME. Just getting it into attributes (maybe a list) would be a good start.

Any thoughts appreciated. Python is not exactly my strong suit!


7 replies

Userlevel 3
Badge +17

HI @Mark2AtSafe, depending on how you use the sequence in the following process,

1. Store the elements into a nested list

    for i, s in enumerate(array):
        for j, v in enumerate(s):
            feature.setAttribute('_list{%d}.sub{%d}' % (i, j), v)

2. Store the elements into a simple list

    for i, v in enumerate(sum(array, [])):
        feature.setAttribute('_list{%d}' % i, v)

3. Concatenate the elements to form a comma-separated string

    feature.setAttribute('_concat', ','.join([str(v) for v in sum(array, [])]))

Hope this helps.

Userlevel 4
Badge +25

HI @Mark2AtSafe, depending on how you use the sequence in the following process,

1. Store the elements into a nested list

    for i, s in enumerate(array):
        for j, v in enumerate(s):
            feature.setAttribute('_list{%d}.sub{%d}' % (i, j), v)

2. Store the elements into a simple list

    for i, v in enumerate(sum(array, [])):
        feature.setAttribute('_list{%d}' % i, v)

3. Concatenate the elements to form a comma-separated string

    feature.setAttribute('_concat', ','.join([str(v) for v in sum(array, [])]))

Hope this helps.

Thanks @takashi- that's great. I've no idea of quite how I'm going to use these inside FME, but getting the values in there is a big part of the battle. Makes me wish I had more time to work with Python!

Userlevel 4
Badge +25

HI @Mark2AtSafe, depending on how you use the sequence in the following process,

1. Store the elements into a nested list

    for i, s in enumerate(array):
        for j, v in enumerate(s):
            feature.setAttribute('_list{%d}.sub{%d}' % (i, j), v)

2. Store the elements into a simple list

    for i, v in enumerate(sum(array, [])):
        feature.setAttribute('_list{%d}' % i, v)

3. Concatenate the elements to form a comma-separated string

    feature.setAttribute('_concat', ','.join([str(v) for v in sum(array, [])]))

Hope this helps.

Just so you can see where I used it... here's the workspace:

0684Q00000ArMh2QAF.jpg

And here's the output:

0684Q00000ArMm8QAF.jpg

Am going to try and use it as the basis for a spatial sort (and ability to group polygons on a spatial basis)

Userlevel 3
Badge +17

Interesting. I picked up a Python function from this web page: Hilbert Curve Concepts & Implementation, and tested that with this script.

# PythonCaller Script Example: Create a Hirbert Curve
import fme, fmeobjects
class HirbertCurveCreator(object):
    def input(self, feature):
        # Collect nodes of a Hirbert Curve
        # Based on a function provided in this web page.
        # http://www.fundza.com/algorithmic/space_filling/h...
        nodes = []
        def hilbert(x0, y0, xi, xj, yi, yj, n):
            if n <= 0:
                X = x0 + (xi + yi)/2
                Y = y0 + (xj + yj)/2
                nodes.append((X, Y))
            else:
                hilbert(x0,           y0,           yi/2,  yj/2,  xi/2,  xj/2, n-1)
                hilbert(x0+xi/2,      y0+xj/2,      xi/2,  xj/2,  yi/2,  yj/2, n-1)
                hilbert(x0+xi/2+yi/2, y0+xj/2+yj/2, xi/2,  xj/2,  yi/2,  yj/2, n-1)
                hilbert(x0+xi/2+yi,   y0+xj/2+yj,  -yi/2, -yj/2, -xi/2, -xj/2, n-1)
                
        x = float(feature.getAttribute('_xmin')) # minimum X of the extents
        y = float(feature.getAttribute('_ymin')) # minimum Y of the extents
        s = float(feature.getAttribute('_size')) # size of the extents (> 0)
        n = int(feature.getAttribute('_iterations')) # iterations
        hilbert(x, y, s, 0, 0, s, n)
        
        # Create a Hirbert Curve as a line geometry.
        feature.setGeometry(fmeobjects.FMELine(nodes))
        self.pyoutput(feature)

iterations = 4, the background gray square is the extents specified by xmin, ymin and size.

0684Q00000ArLq6QAF.png

Badge +16

Mark you're off down a wormhole, are you sure you can't leverage however you guys do spatial indexing? You can call ArcGIS's Sort geoprocessing tool tool and the Peano option if you want to expose some proxy for proximity with the same limitations as Hilbert.

Userlevel 4
Badge +25

Mark you're off down a wormhole, are you sure you can't leverage however you guys do spatial indexing? You can call ArcGIS's Sort geoprocessing tool tool and the Peano option if you want to expose some proxy for proximity with the same limitations as Hilbert.

Hey Bruce. You're right, of course. But if I want to go deeper into FME I'd need to get the developers involved, and right now I'm just mullocking around with some ideas on a lazy Sunday afternoon. If I manage to create something that works, and if anybody found it useful, then I'll take it to the dev team and ask them to create a better solution.

Userlevel 4
Badge +25

Interesting. I picked up a Python function from this web page: Hilbert Curve Concepts & Implementation, and tested that with this script.

# PythonCaller Script Example: Create a Hirbert Curve
import fme, fmeobjects
class HirbertCurveCreator(object):
    def input(self, feature):
        # Collect nodes of a Hirbert Curve
        # Based on a function provided in this web page.
        # http://www.fundza.com/algorithmic/space_filling/h...
        nodes = []
        def hilbert(x0, y0, xi, xj, yi, yj, n):
            if n <= 0:
                X = x0 + (xi + yi)/2
                Y = y0 + (xj + yj)/2
                nodes.append((X, Y))
            else:
                hilbert(x0,           y0,           yi/2,  yj/2,  xi/2,  xj/2, n-1)
                hilbert(x0+xi/2,      y0+xj/2,      xi/2,  xj/2,  yi/2,  yj/2, n-1)
                hilbert(x0+xi/2+yi/2, y0+xj/2+yj/2, xi/2,  xj/2,  yi/2,  yj/2, n-1)
                hilbert(x0+xi/2+yi,   y0+xj/2+yj,  -yi/2, -yj/2, -xi/2, -xj/2, n-1)
                
        x = float(feature.getAttribute('_xmin')) # minimum X of the extents
        y = float(feature.getAttribute('_ymin')) # minimum Y of the extents
        s = float(feature.getAttribute('_size')) # size of the extents (> 0)
        n = int(feature.getAttribute('_iterations')) # iterations
        hilbert(x, y, s, 0, 0, s, n)
        
        # Create a Hirbert Curve as a line geometry.
        feature.setGeometry(fmeobjects.FMELine(nodes))
        self.pyoutput(feature)

iterations = 4, the background gray square is the extents specified by xmin, ymin and size.

0684Q00000ArLq6QAF.png

Nice. I got my script from here. As you see, it returns an array, which is what I was having trouble converting to FME. Your solution is probably way more elegant than my script/workspace hack.

Reply