Skip to main content
Question

Clustering Points Based on Total Hours and Spatial Parameters

  • February 13, 2025
  • 3 replies
  • 48 views

sahan969
Participant
Forum|alt.badge.img+2

Hi everyone,

I am new to FME and need some assistance with a project. I am trying to create clusters based on a point layer, using one of the parameters where the total hours equal to 'n' and a spatial parameter. The objective is to find clusters where the total hours equal 'n' and ultimately demarcate boundaries for these clusters to optimal coverage. 

I have been using the NeighborFinder transformer, but I am having trouble moving forward. Could anyone provide guidance or suggest a better approach to achieve this?

Thank you in advance for your help!
Sahan

3 replies

hkingsbury
Celebrity
Forum|alt.badge.img+50
  • Celebrity
  • February 16, 2025

There’s a bit of a discussion here on spatial grouping - 

 

You could also look at the SpatialSorter - https://docs.safe.com/fme/html/FME-Form-Documentation/FME-Transformers/Transformers/spatialsorter.htm

 

An approach using the SpatialSorter could be you sort the features, then keep a running total of you hours. You can do that with the below python:

 

import fme
from fme import BaseTransformer
import fmeobjects


class FeatureProcessor(BaseTransformer):
    """Template Class Interface:
    When using this class, make sure its name is set as the value of the 'Class to Process Features'
    transformer parameter.

    This class inherits from 'fme.BaseTransformer'. For full details of this class, its methods, and
    expected usage, see https://docs.safe.com/fme/html/fmepython/api/fme.html#fme.BaseTransformer.
    """

    def __init__(self):
        """Base constructor for class members."""
        self.runningTotal = 0
        self.maxTotal = int(FME_MacroValues['maxHours'] )
        self.curGroup = 0
        pass

    def has_support_for(self, support_type: int):
        """This method is called by FME to determine if the PythonCaller supports Bulk mode,
        which allows for significant performance gains when processing large numbers of features.
        """
        return support_type == fmeobjects.FME_SUPPORT_FEATURE_TABLE_SHIM

    def input(self, feature: fmeobjects.FMEFeature):
        """This method is called for each feature which enters the PythonCaller."""
        self.runningTotal += int(feature.getAttribute('hours'))

        if self.runningTotal > self.maxTotal:
            self.curGroup += 1
            self.runningTotal = int(feature.getAttribute('hours'))

        feature.setAttribute('Group', self.curGroup)
        self.pyoutput(feature, output_tag="PYOUTPUT")

    def close(self):
        """This method is called once all the FME Features have been processed from input()."""
        pass

    def process_group(self):
        """This method is called by FME for each group when group processing mode is enabled."""
        pass

    def reject_feature(self, feature: fmeobjects.FMEFeature, code: str, message: str):
        """This method can be used to output a feature to the <Rejected> port."""
        feature.setAttribute("fme_rejection_code", code)
        feature.setAttribute("fme_rejection_message", message)
        self.pyoutput(feature, output_tag="<Rejected>")

 


koulsoum
Contributor
Forum|alt.badge.img+10
  • Contributor
  • February 17, 2025

Hi ​@sahan969 ,

I would proceed in three steps:

1. Spatial filtering :
In the NeighborFinder you can set Input to Candidates Only.In Max Distance set a value for the radius within which you are searching for neighbors. Check Generate a list to have a list of neighbors for each point while keeping ‘total hours’ info with Selected Attributes (you can also keep an object ID or the coordinates if you want) .

Then, create a ‘Neighbor_ID’ to link neighboring points together, using a Counter, for example. Finally, explode the list using ListExploder.

2. Attribute filtering:
Retrieve the points that are both neighbors and have the same total hours value. I would use Matcher, grouping by ‘Neighbor_ID’ and selecting  ‘total hours’ as the attribute. This gives the matched points, forming the clusters.

3. Grouping clusters (Aggregator):
Use Aggregator, grouping by ‘_match_id’, to merge the clusters. Be careful, as Aggregator may modify some attributes.

There are multiple ways to achieve this, and this is one approach I suggest.


liamfez
Influencer
Forum|alt.badge.img+34
  • Influencer
  • February 17, 2025

The HullAccumulator with group processing may also be helpful if you are trying to turn the grouped points into areas.


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings