graph LR
T[Thematic Data] --> Aligner
R[Reference Data] --> Aligner
Aligner --> P{Processor}
P --> Res[AlignerResult]
Aligner
aligner.Aligner(processor=None, crs=DEFAULT_CRS, config=None, feedback=None)Compares and aligns thematic geospatial data against a set of reference data.
The Aligner manages the loading of both thematic and reference data, configures the geometric processing rules, and executes the alignment, prediction, and evaluation logic across a series of relevant distances.
Attributes
| Name | Type | Description |
|---|---|---|
| logger | Logger | Instance for logging feedback and information. |
| log_metadata | bool | If True, metadata about the actuation is logged in the results. |
| add_observations | bool | If True, process result observations will be computed by default. |
| processor | BaseProcessor or AlignerGeometryProcessor | The geometric processor used for alignment calculations. |
| correction_distance | float | Distance used in buffer operations to remove slivers (technical correction). |
| mitre_limit | int | Parameter for the buffer operation to control the maximum length of join corners. |
| max_workers | (int, optional) | The maximum number of workers for parallel execution (ThreadPoolExecutor). |
| crs | str | The Coordinate Reference System (CRS) being used (bv. ‘EPSG:31370’). |
| name_thematic_id | str | Name of the identifier field for thematic data. |
| diff_metric | DiffMetric | The metric used to measure differences between geometries (bv. area change). |
| reference_data | (AlignerFeatureCollection, optional) | Loaded collection of reference features. |
| thematic_data | (AlignerFeatureCollection, optional) | Loaded collection of thematic features. |
Notes
The Aligner acts as the central orchestrator of the brdr package. It connects data loaders with geometric processors.
Examples
>>> from brdr.aligner import Aligner
>>> aligner = Aligner(crs="EPSG:31370")
>>> aligner.load_thematic_data(my_features)
>>> results = aligner.align(relevant_distances=[0.5, 1.0])Methods
| Name | Description |
|---|---|
| compare_to_reference | Calculates observation-related information based on the input geometry. |
| evaluate | Evaluates input geometries against predictions using observation matching |
| get_difference_metrics_for_thematic_data | Calculates difference metrics for thematic elements across a series of distances. |
| load_reference_data | Loads the reference features into the aligner and prepares them for processing. |
| load_thematic_data | Loads the thematic features into the aligner using a specific loader. |
| predict | Predicts the ‘most interesting’ relevant distances for changes in thematic |
| process | Executes the alignment process across multiple relevant distances. |
compare_to_reference
aligner.Aligner.compare_to_reference(geometry, with_geom=False)Calculates observation-related information based on the input geometry.
This method performs a spatial analysis to determine how much of the input geometry is covered by reference features and identifies which specific reference elements are involved. It also detects “OD” (Onbekend Terrein/Open Space) areas that are not covered by any reference data.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| geometry | BaseGeometry | The input geometry to be analyzed against the reference dataset. | required |
| with_geom | bool | If True, includes the GeoJSON representation of each intersection and the OD-area in the output. Defaults to False. | False |
Returns
| Name | Type | Description |
|---|---|---|
| Dict[str, Any] | A dictionary containing the alignment analysis: - alignment_date (str): Timestamp of the calculation. - brdr_version (str): Version of the package used. - full (bool): True if the geometry is entirely composed of complete reference features. - area (float): Total area of the input geometry. - last_version_date (str, optional): The most recent version date found among the intersected reference features. - reference_features (dict): A mapping of reference IDs to: - full (bool): True if the reference feature is fully contained. - area (float): Area of the intersection. - percentage (float): Coverage percentage relative to the reference. - geometry (str, optional): GeoJSON string (if with_geom is True). - reference_od (dict, optional): Description of areas not covered by reference features, containing ‘area’ and optionally ‘geometry’. |
Notes
The method uses a spatial index (R-tree) to efficiently find intersecting reference features. A correction distance is applied to the “OD” calculation to filter out insignificant slivers.
graph TD
In[Input Geometry] --> Query[Spatial Index Query]
Query --> Intersect[Calculate Intersections]
Intersect --> Stats[Compute Area & %]
In --> Diff[Difference with Union of Refs]
Diff --> OD[Identify Unknown Area / OD]
Stats --> Dict[Final observation Dictionary]
OD --> Dict
Examples
>>> info = aligner.compare_to_reference(my_geom, with_geom=True)
>>> print(info["full"])
>>> print(info["reference_features"].keys()) # IDs of intersected refsevaluate
aligner.Aligner.evaluate(
relevant_distances=None,
*,
thematic_ids=None,
metadata_field=METADATA_FIELD_NAME,
full_reference_strategy=FullReferenceStrategy.NO_FULL_REFERENCE,
max_predictions=-1,
multi_to_best_prediction=True,
)Evaluates input geometries against predictions using observation matching and selection strategies.
This method identifies the best candidate geometries for alignment by comparing predicted geometries against the original attributes and reference data. It tags results with evaluation labels (e.g., PREDICTION_UNIQUE) to facilitate decision-making.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| relevant_distances | Iterable[float] | Distances to evaluate. Defaults to 0.0m to 3.0m (step 0.1m). | None |
| thematic_ids | List[ThematicId] | List of IDs to evaluate. If None, all loaded thematic features are processed. Features not in this list are marked as NOT_EVALUATED. | None |
| metadata_field | str | The field name containing the metadata of the input geometry. Defaults to METADATA_FIELD_NAME. | METADATA_FIELD_NAME |
| full_reference_strategy | FullReferenceStrategy | Strategy to prioritize predictions based on their ‘fullness’ relative to reference data. Defaults to NO_FULL_REFERENCE. | FullReferenceStrategy.NO_FULL_REFERENCE |
| max_predictions | int | Maximum number of predictions to return per feature. -1 returns all candidates. Defaults to -1. | -1 |
| multi_to_best_prediction | bool | If True and max_predictions=1, returns the candidate with the highest score. If False, returns the original geometry when multiple candidates exist. Defaults to True. |
True |
Returns
| Name | Type | Description |
|---|---|---|
| AlignerResult | An object containing evaluated results with detailed metadata and evaluation status tags. |
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If provided thematic_ids are not present in the thematic data. |
Notes
The evaluation logic follows a specific priority tree: 1. observation Match: If a prediction matches the base observation exactly, it is prioritized (score 100). 2. Fullness: If a strategy is set, ‘full’ predictions get a score boost. 3. Scoring: Candidates are ranked by their prediction score. 4. Selection: Based on max_predictions, the best candidates are selected.
graph TD
Start[Start Evaluation] --> Pred[Generate Predictions]
Pred --> Match{observation Match?}
Match -- Yes --> HighScore[Prioritize & Score 100]
Match -- No --> Full{Full Reference?}
Full -- Yes --> Strategy[Apply Fullness Strategy]
Full -- No --> Rank[Rank by Prediction Score]
Strategy --> Rank
HighScore --> Rank
Rank --> Select{Max Predictions?}
Select --> Final[Return AlignerResult]
Examples
>>> aligner = Aligner()
>>> # Evaluate with a limit of 1 best prediction per feature
>>> results = aligner.evaluate(thematic_ids=["id_01"],full_reference_strategy=FullReferenceStrategy.ONLY_FULL_REFERENCE,max_predictions=1)get_difference_metrics_for_thematic_data
aligner.Aligner.get_difference_metrics_for_thematic_data(
dict_processresults=None,
thematic_data=None,
diff_metric=DiffMetric.SYMMETRICAL_AREA_CHANGE,
)Calculates difference metrics for thematic elements across a series of distances.
This method iterates through the processed results and compares the resulting geometries against their original thematic counterparts. It uses the spatial context of the reference data to calculate metrics like area change or symmetrical difference.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| dict_processresults | Dict[ThematicId, Dict[float, Optional[ProcessResult]]] | A nested dictionary where keys are thematic IDs and values are dictionaries mapping relevant distances to ProcessResult[] objects. Required if not provided via internal state. |
None |
| thematic_data | AlignerFeatureCollection | The collection containing the original thematic geometries. Defaults to self.thematic_data. |
None |
| diff_metric | DiffMetric | The metric used to quantify the geometric change. Defaults to DiffMetric.SYMMETRICAL_AREA_CHANGE. |
DiffMetric.SYMMETRICAL_AREA_CHANGE |
Returns
| Name | Type | Description |
|---|---|---|
| Dict[ThematicId, Dict[float, float]] | A nested dictionary where each thematic ID maps to a dictionary of distances and their corresponding calculated metric values. |
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If dict_processresults is not provided and cannot be resolved. |
Notes
The calculation involves three primary geometric components: 1. Original Geometry: The thematic feature before alignment. 2. Result Geometry: The feature after alignment at a specific distance. 3. Reference Union: The combined geometry of all reference data, used to contextualize the change.
graph LR
PR[Process Results] --> Calc[Metric Calculator]
Orig[Original Geometries] --> Calc
Ref[Reference Union] --> Calc
Calc --> Output[Distance-Metric Map]
Examples
>>> metrics = aligner.get_difference_metrics_for_thematic_data(
... dict_processresults=my_results,
... diff_metric=DiffMetric.AREA_CHANGE
... )
>>> # Get area change for feature 'A' at distance 0.5
>>> print(metrics['A'][0.5])
### load_reference_data { #brdr.aligner.Aligner.load_reference_data }
```python
aligner.Aligner.load_reference_data(loader)
Loads the reference features into the aligner and prepares them for processing.
This method retrieves data via the provided loader, synchronizes the CRS, and marks the feature collection as a reference dataset to enable spatial indexing and comparison logic.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| loader | Loader | An instance of a Loader class (e.g., WFSReferenceLoader) that implements the load_data interface. |
required |
Notes
Setting is_reference = True on the resulting dataset is essential for the internal alignment logic, as it distinguishes the ‘anchor’ geometries from the thematic geometries that need to be shifted.
Examples
>>> from brdr.loader import WFSReferenceLoader
>>> ref_loader = WFSReferenceLoader(url="https://geoserver.com/wfs")
>>> aligner.load_reference_data(ref_loader)
>>> print(aligner.reference_data.is_reference)
Trueload_thematic_data
aligner.Aligner.load_thematic_data(loader)Loads the thematic features into the aligner using a specific loader.
This method executes the loader’s data retrieval logic and ensures that the resulting feature collection is tagged with the Aligner’s CRS.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| loader | Loader | An instance of a Loader class (e.g., GeoJsonLoader or WFSReferenceLoader) that implements the load_data interface. |
required |
Notes
The method automatically synchronizes the CRS of the loaded data with the self.crs attribute of the Aligner instance.
Examples
>>> from brdr.loader import GeoJsonLoader
>>> loader = GeoJsonLoader(path="data/themes.json")
>>> aligner.load_thematic_data(loader)predict
aligner.Aligner.predict(
relevant_distances=None,
*,
thematic_ids=None,
diff_metric=None,
)Predicts the ‘most interesting’ relevant distances for changes in thematic elements.
This method analyzes the stability of geometric differences across a range of distances. It identifies “breakpoints” where changes occur and “zero-streaks” where the geometry remains stable. Based on this, a prediction score is assigned to specific results.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| relevant_distances | List[float] or np.ndarray | A series of distances (in meters) to be analyzed. Defaults to a range from 0.0 to 3.0 meters with steps of 0.1m. | None |
| thematic_ids | List[ThematicId] | Specific thematic IDs to process. If None, all loaded thematic geometries are used. | None |
| diff_metric | DiffMetric | The metric used to determine differences (e.g., area change). If None, the Aligner’s default diff_metric is used. |
None |
Returns
| Name | Type | Description |
|---|---|---|
| AlignerResult | A result object containing the process results enriched with stability properties and prediction scores. |
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If provided thematic_ids are not found in the loaded data. |
Notes
The prediction logic follows a four-step process: 1. Series Processing: Calculates results for all specified distances. 2. Metric Calculation: Computes the difference between original and result for each step. 3. Stability Analysis: Identifies streaks where the change is minimal (zero-streaks) or where the metric flips sign (breakpoints). 4. Scoring: Assigns a PREDICTION_SCORE to results that fall within a significant stability window.
graph TD
A[Input Distances] --> B[Process Series]
B --> C[Calculate Diffs]
C --> D[Stability Analysis]
D --> E{Stable?}
E -- Yes --> F[Assign Prediction Score]
E -- No --> G[Mark unstable]
F --> H[AlignerResult]
G --> H
Examples
>>> aligner = Aligner(crs="EPSG:31370")
>>> # Predict using default distance range
>>> prediction_results = aligner.predict(thematic_ids=["id_1", "id_2"])process
aligner.Aligner.process(
relevant_distances=None,
*,
thematic_ids=None,
max_workers=None,
)Executes the alignment process across multiple relevant distances.
This method iterates through the specified thematic features and calculates the alignment for each provided ‘relevant distance’. It can utilize parallel processing via a ThreadPoolExecutor to speed up calculations.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| relevant_distances | Iterable[float] | A series of distances (in meters) to use for the alignment logic. This parameter is mandatory. | None |
| thematic_ids | List[ThematicId] | A specific list of IDs to process. If None, all thematic features currently loaded in the aligner will be processed. | None |
| max_workers | int | The number of threads for parallel execution. If -1, execution is serial. If None, the Aligner’s default max_workers is used. |
None |
Returns
| Name | Type | Description |
|---|---|---|
| [AlignerResult][] | An object containing the structured results, accessible by thematic ID and relevant distance. |
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If relevant_distances is None or empty. If any provided thematic_ids are not found in the loaded thematic data. |
Notes
The processing flow involves distributing geometry-distance pairs across available worker threads:
graph TD
Start[Process Call] --> Check{Valid IDs?}
Check -- Yes --> Parallel{max_workers > 0?}
Parallel -- Yes --> Workers[ThreadPoolExecutor]
Parallel -- No --> Serial[Single Thread]
Workers --> Proc[Geometry Processor]
Serial --> Proc
Proc --> Result[AlignerResult]
Examples
>>> aligner.process(relevant_distances=[0, 0.5, 1.0], max_workers=4)
<brdr.aligner.AlignerResult object at ...>