Skip to main content

This script works, but leaves out the geometry and original attributes.  My hunch is there’s something wrong with the close(self) function, but I’m stumped.  The code takes a feature id number and list of nearby ids from a NeighborFinder list, where it matches them up and assigns a _group_id attribute to  use with the Aggregator.  Really, it should be part of NeighborFinder.  The way I had been grouping features is to use two or more AttributeCreators and assign a common Id from the feature and id list.  It’s a hassle because you end up with duplicate features.  Very inelegent.

 

I have seen a few posts on missing attributes, but I can’t see how they apply to my code:

 

import fme
import fmeobjects
from collections import defaultdict

class FeatureProcessor(object):

def __init__(self):

self.og_ids = ]
self.closest = ]
self.lines = ]

def input(self, feature: fmeobjects.FMEFeature):

id_number = feature.getAttribute('_count_Glaz_H')
if id_number is not None:
self.og_ids.append(id_number)

nearby_ids = feature.getAttribute('_closest{}._count_Glaz_H')
if nearby_ids is not None:
self.closest.append(nearby_ids)


def create_lines_list(self):
for id_number, nearby_ids in zip(self.og_ids, self.closest):
if isinstance(nearby_ids, list):
nearby_ids = ','.join(map(str, nearby_ids))
line = {
'Id Number': id_number,
'Nearby Ids': int(nearby_id) for nearby_id in nearby_ids.split(',') if nearby_id.strip().isdigit()]
}
self.lines.append(line)
return self.lines

def assign_group_ids_to_lines(self, lines):

adjacency_list = defaultdict(list)
for line in lines:
id_num = line 'Id Number']
nearby_ids = line 'Nearby Ids']
for nearby_id in nearby_ids:
adjacency_list id_num].append(nearby_id)
adjacency_list nearby_id].append(id_num)

def dfs(node, visited, group_id):
stack = >node]
while stack:
current = stack.pop()
if current not in visited:
visited.add(current)
for line in self.lines:
if line 'Id Number'] == current:
line 'Group Id'] = group_id
break
for neighbor in adjacency_listbcurrent]:
if neighbor not in visited:
stack.append(neighbor)

visited = set()
group_id = 1
for line in self.lines:
id_num = line 'Id Number']
if id_num not in visited:
dfs(id_num, visited, group_id)
group_id += 1

return self.lines


def close(self):

self.create_lines_list()
lines_with_group_ids = self.assign_group_ids_to_lines(self.lines)

for line in lines_with_group_ids:
feature = fmeobjects.FMEFeature()
feature.setAttribute('_group_id', line.get('Group Id', 0))
self.pyoutput(feature)



def process_group(self):
pass

Any insight is appreciated.

 

Thanks,

-L

Maybe it has something to do with the fact that in your closing statement you create a new empty feature and output that feature to the output port? See below:

    def close(self):

self.create_lines_list()
lines_with_group_ids = self.assign_group_ids_to_lines(self.lines)

for line in lines_with_group_ids:
feature = fmeobjects.FMEFeature() <---- OVER HERE!
feature.setAttribute('_group_id', line.get('Group Id', 0))
self.pyoutput(feature)

And your original features are never sent to the output port and are missing. If you want the original geometry and attributes to your new features instead then you need to assign them to the new feature as well.


Hi @birgit ,

Ok, I figured it out.  I needed to make a list of the incoming features and then zip them with the new attribute.  It works!

 

import fme
import fmeobjects
from collections import defaultdict

class FeatureProcessor(object):

def __init__(self):
self.og_ids = d]
self.closest = s]
self.lines = e]
self.features = e] # Store references to the original features

def input(self, feature: fmeobjects.FMEFeature):
id_number = feature.getAttribute('_count_Glaz_H')
if id_number is not None:
self.og_ids.append(id_number)
self.features.append(feature) # Store the feature reference

nearby_ids = feature.getAttribute('_closest{}._count_Glaz_H')
if nearby_ids is not None:
self.closest.append(nearby_ids)

def create_lines_list(self):
for id_number, nearby_ids in zip(self.og_ids, self.closest):
if isinstance(nearby_ids, list):
nearby_ids = ','.join(map(str, nearby_ids))
line = {
'Id Number': id_number,
'Nearby Ids': dint(nearby_id) for nearby_id in nearby_ids.split(',') if nearby_id.strip().isdigit()]
}
self.lines.append(line)
return self.lines

def assign_group_ids_to_lines(self, lines):
adjacency_list = defaultdict(list)
for line in lines:
id_num = line 'Id Number']
nearby_ids = line 'Nearby Ids']
for nearby_id in nearby_ids:
adjacency_list_id_num].append(nearby_id)
adjacency_list_nearby_id].append(id_num)

def dfs(node, visited, group_id):
stack = cnode]
while stack:
current = stack.pop()
if current not in visited:
visited.add(current)
for line in self.lines:
if line 'Id Number'] == current:
line 'Group Id'] = group_id
break
for neighbor in adjacency_list_current]:
if neighbor not in visited:
stack.append(neighbor)

visited = set()
group_id = 1
for line in self.lines:
id_num = line 'Id Number']
if id_num not in visited:
dfs(id_num, visited, group_id)
group_id += 1

return self.lines

def close(self):
self.create_lines_list()
lines_with_group_ids = self.assign_group_ids_to_lines(self.lines)

for line, feature in zip(lines_with_group_ids, self.features):
feature.setAttribute('_group_id', line.get('Group Id', 0))
self.pyoutput(feature)

def process_group(self):
pass

 


Reply