Skip to content

Commit bdd22c9

Browse files
fix: update provider registration
1 parent 8cc49af commit bdd22c9

4 files changed

Lines changed: 153 additions & 147 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
from .extract_basal_contacts import BasalContactsAlgorithm
2-
from .sorter import StratigraphySorterAlgorithm
2+
from .sorter import UserDefinedStratigraphyAlgorithm
33
from .thickness_calculator import ThicknessCalculatorAlgorithm
44
from .sampler import SamplerAlgorithm

m2l/processing/algorithms/sorter.py

Lines changed: 149 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
QgsProcessingParameterEnum,
1616
QgsProcessingParameterFeatureSink,
1717
QgsProcessingParameterFeatureSource,
18+
QgsProcessingParameterMatrix,
1819
QgsVectorLayer,
19-
QgsWkbTypes
20+
QgsWkbTypes,
21+
QgsSettings
2022
)
21-
23+
from ...main.vectorLayerWrapper import qgsLayerToDataFrame
24+
import json
2225
# ────────────────────────────────────────────────
2326
# map2loop sorters
2427
# ────────────────────────────────────────────────
@@ -41,15 +44,135 @@
4144
"Observation projections": SorterObservationProjections,
4245
}
4346

44-
class StratigraphySorterAlgorithm(QgsProcessingAlgorithm):
47+
# class AutomaticStratigraphyAlgorithm(QgsProcessingAlgorithm):
48+
# """
49+
# Creates a one-column ‘stratigraphic column’ table ordered
50+
# by the selected map2loop sorter.
51+
# """
52+
# METHOD = "METHOD"
53+
# INPUT_GEOLOGY = "INPUT_GEOLOGY"
54+
# INPUT_STRATI_COLUMN = "INPUT_STRATI_COLUMN"
55+
# SORTING_ALGORITHM = "SORTING_ALGORITHM"
56+
# OUTPUT = "OUTPUT"
57+
58+
# # ----------------------------------------------------------
59+
# # Metadata
60+
# # ----------------------------------------------------------
61+
# def name(self) -> str:
62+
# return "loop_sorter"
63+
64+
# def displayName(self) -> str:
65+
# return "Stratigraphy Tools: Automatic Stratigraphic Column"
66+
67+
# def group(self) -> str:
68+
# return "Stratigraphy Tools"
69+
70+
# def groupId(self) -> str:
71+
# return "Loop3d"
72+
73+
# # ----------------------------------------------------------
74+
# # Parameters
75+
# # ----------------------------------------------------------
76+
# def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
77+
78+
# self.addParameter(
79+
# QgsProcessingParameterFeatureSource(
80+
# self.INPUT_GEOLOGY,
81+
# "Geology polygons",
82+
# [QgsProcessing.TypeVectorPolygon],
83+
# )
84+
# )
85+
86+
# strati_settings = QgsSettings()
87+
# last_strati_column = strati_settings.value("m2l/strati_column", "")
88+
# self.addParameter(
89+
# QgsProcessingParameterMatrix(
90+
# name=self.INPUT_STRATI_COLUMN,
91+
# description="Stratigraphic Order",
92+
# headers=["Unit"],
93+
# numberRows=0,
94+
# defaultValue=last_strati_column
95+
# )
96+
# )
97+
98+
# # enum so the user can pick the strategy from a dropdown
99+
# self.addParameter(
100+
# QgsProcessingParameterEnum(
101+
# self.SORTING_ALGORITHM,
102+
# "Sorting strategy",
103+
# options=list(SORTER_LIST.keys()),
104+
# defaultValue=0, # Age-based is safest default
105+
# )
106+
# ) #:contentReference[oaicite:0]{index=0}
107+
108+
# self.addParameter(
109+
# QgsProcessingParameterFeatureSink(
110+
# self.OUTPUT,
111+
# "Stratigraphic column",
112+
# )
113+
# )
114+
115+
# # ----------------------------------------------------------
116+
# # Core
117+
# # ----------------------------------------------------------
118+
# def processAlgorithm(
119+
# self,
120+
# parameters: dict[str, Any],
121+
# context: QgsProcessingContext,
122+
# feedback: QgsProcessingFeedback,
123+
# ) -> dict[str, Any]:
124+
125+
# # 1 ► fetch user selections
126+
# geology: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
127+
# algorithm_index: int = self.parameterAsEnum(parameters, self.ALGO, context)
128+
# sorter_class = list(SORTER_LIST.values())[algorithm_index]
129+
130+
# feedback.pushInfo(f"Using sorter: {sorter_class.__name__}")
131+
132+
# # 2 ► convert QGIS layers / tables to pandas
133+
# # geology =
134+
135+
# # 3 ► run the sorter
136+
# # sorter = sorter_cls() # instantiation is always zero-argument
137+
# # order = sorter.sort(
138+
# # units_df,
139+
# # relationships_df,
140+
# # contacts_df,
141+
# # map_data,
142+
# # )
143+
144+
# # 4 ► write an in-memory table with the result
145+
# sink_fields = QgsFields()
146+
# sink_fields.append(QgsField("strat_pos", int))
147+
# sink_fields.append(QgsField("unit_name", str))
148+
149+
# (sink, dest_id) = self.parameterAsSink(
150+
# parameters,
151+
# self.OUTPUT,
152+
# context,
153+
# sink_fields,
154+
# QgsWkbTypes.NoGeometry,
155+
# geology.sourceCrs(),
156+
# )
157+
158+
# for pos, name in enumerate(order, start=1):
159+
# f = QgsFeature(sink_fields)
160+
# f.setAttributes([pos, name])
161+
# sink.addFeature(f, QgsFeatureSink.FastInsert)
162+
163+
# return {self.OUTPUT: dest_id}
164+
165+
# # ----------------------------------------------------------
166+
# def createInstance(self) -> QgsProcessingAlgorithm:
167+
# return __class__()
168+
169+
170+
class UserDefinedStratigraphyAlgorithm(QgsProcessingAlgorithm):
45171
"""
46172
Creates a one-column ‘stratigraphic column’ table ordered
47173
by the selected map2loop sorter.
48174
"""
49-
METHOD = "METHOD"
50-
INPUT_GEOLOGY = "INPUT_GEOLOGY"
51175
INPUT_STRATI_COLUMN = "INPUT_STRATI_COLUMN"
52-
SORTING_ALGORITHM = "SORTING_ALGORITHM"
53176
OUTPUT = "OUTPUT"
54177

55178
# ----------------------------------------------------------
@@ -59,63 +182,35 @@ def name(self) -> str:
59182
return "loop_sorter"
60183

61184
def displayName(self) -> str:
62-
return "Loop3d: Stratigraphic sorter"
185+
return "Stratigraphy: User-Defined Stratigraphic Column"
63186

64187
def group(self) -> str:
65-
return "Loop3d"
188+
return "Stratigraphy"
66189

67190
def groupId(self) -> str:
68-
return "Loop3d"
69-
70-
def updateParameters(self, parameters):
71-
selected_method = parameters.get(self.METHOD, 0)
72-
if selected_method == 0: # User-Defined selected
73-
self.parameterDefinition(self.INPUT_STRATI_COLUMN).setMetadata({'widget_wrapper': {'visible': True}})
74-
self.parameterDefinition(self.SORTING_ALGORITHM).setMetadata({'widget_wrapper': {'visible': False}})
75-
self.parameterDefinition(self.INPUT_GEOLOGY).setMetadata({'widget_wrapper': {'visible': False}})
76-
else: # Automatic selected
77-
self.parameterDefinition(self.INPUT_GEOLOGY).setMetadata({'widget_wrapper': {'visible': True}})
78-
self.parameterDefinition(self.SORTING_ALGORITHM).setMetadata({'widget_wrapper': {'visible': True}})
79-
self.parameterDefinition(self.INPUT_STRATI_COLUMN).setMetadata({'widget_wrapper': {'visible': False}})
80-
81-
return super().updateParameters(parameters)
191+
return "Stratigraphy_Column"
82192

83193
# ----------------------------------------------------------
84194
# Parameters
85195
# ----------------------------------------------------------
86196
def initAlgorithm(self, config: Optional[dict[str, Any]] = None) -> None:
87-
88-
self.addParameter(
89-
QgsProcessingParameterEnum(
90-
name=self.METHOD,
91-
description='Select Method',
92-
options=['User-Defined', 'Automatic'],
93-
defaultValue=0
94-
)
95-
)
96-
self.addParameter(
97-
QgsProcessingParameterFeatureSource(
98-
self.INPUT_GEOLOGY,
99-
"Geology polygons",
100-
[QgsProcessing.TypeVectorPolygon],
101-
)
102-
)
103197

104-
105-
# enum so the user can pick the strategy from a dropdown
198+
strati_settings = QgsSettings()
199+
last_strati_column = strati_settings.value("m2l/strati_column", "")
106200
self.addParameter(
107-
QgsProcessingParameterEnum(
108-
self.ALGO,
109-
"Sorting strategy",
110-
options=list(SORTER_LIST.keys()),
111-
defaultValue=0, # Age-based is safest default
201+
QgsProcessingParameterMatrix(
202+
name=self.INPUT_STRATI_COLUMN,
203+
description="Stratigraphic Order",
204+
headers=["Unit"],
205+
numberRows=0,
206+
defaultValue=last_strati_column
112207
)
113-
) #:contentReference[oaicite:0]{index=0}
208+
)
114209

115210
self.addParameter(
116211
QgsProcessingParameterFeatureSink(
117212
self.OUTPUT,
118-
self.tr("Stratigraphic column"),
213+
"Stratigraphic column",
119214
)
120215
)
121216

@@ -128,101 +223,15 @@ def processAlgorithm(
128223
context: QgsProcessingContext,
129224
feedback: QgsProcessingFeedback,
130225
) -> dict[str, Any]:
226+
227+
strati_column = self.parameterAsMatrix(parameters, self.INPUT_STRATI_COLUMN, context)
228+
strati_settings = QgsSettings()
229+
last_strati_column = strati_settings.value("m2l/strati_column", "")
131230

132-
# 1 ► fetch user selections
133-
in_layer: QgsVectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
134-
algo_index: int = self.parameterAsEnum(parameters, self.ALGO, context)
135-
sorter_cls = list(SORTER_LIST.values())[algo_index]
136-
137-
feedback.pushInfo(f"Using sorter: {sorter_cls.__name__}")
138-
139-
# 2 ► convert QGIS layers / tables to pandas
140-
# --------------------------------------------------
141-
# You must supply these three DataFrames:
142-
# units_df — required (layerId, name, minAge, maxAge, group)
143-
# relationships_df — required (Index1 / Unitname1, Index2 / Unitname2 …)
144-
# contacts_df — required for all but Age‐based
145-
#
146-
# Typical workflow:
147-
# • iterate over in_layer.getFeatures()
148-
# • build dicts/lists
149-
# • pd.DataFrame(…)
150-
#
151-
# NB: map2loop does *not* need geometries – only attribute values.
152-
# --------------------------------------------------
153-
units_df, relationships_df, contacts_df, map_data = build_input_frames(in_layer, feedback)
154-
155-
# 3 ► run the sorter
156-
sorter = sorter_cls() # instantiation is always zero-argument
157-
order = sorter.sort(
158-
units_df,
159-
relationships_df,
160-
contacts_df,
161-
map_data,
162-
)
163-
164-
# 4 ► write an in-memory table with the result
165-
sink_fields = QgsFields()
166-
sink_fields.append(QgsField("strat_pos", int))
167-
sink_fields.append(QgsField("unit_name", str))
168-
169-
(sink, dest_id) = self.parameterAsSink(
170-
parameters,
171-
self.OUTPUT,
172-
context,
173-
sink_fields,
174-
QgsWkbTypes.NoGeometry,
175-
in_layer.sourceCrs(),
176-
)
177-
178-
for pos, name in enumerate(order, start=1):
179-
f = QgsFeature(sink_fields)
180-
f.setAttributes([pos, name])
181-
sink.addFeature(f, QgsFeatureSink.FastInsert)
231+
json_list = json.dumps(strati_column)
182232

183-
return {self.OUTPUT: dest_id}
233+
return {self.OUTPUT: json_list}
184234

185235
# ----------------------------------------------------------
186236
def createInstance(self) -> QgsProcessingAlgorithm:
187-
return StratigraphySorterAlgorithm()
188-
189-
190-
# -------------------------------------------------------------------------
191-
# Helper stub – you must replace with *your* conversion logic
192-
# -------------------------------------------------------------------------
193-
def build_input_frames(layer: QgsVectorLayer, feedback) -> tuple:
194-
"""
195-
Placeholder that turns the geology layer (and any other project
196-
layers) into the four objects required by the sorter.
197-
198-
Returns
199-
-------
200-
(units_df, relationships_df, contacts_df, map_data)
201-
"""
202-
import pandas as pd
203-
from m2l.map2loop.mapdata import MapData # adjust import path if needed
204-
205-
# Example: convert the geology layer to a very small units_df
206-
units_records = []
207-
for f in layer.getFeatures():
208-
units_records.append(
209-
dict(
210-
layerId=f.id(),
211-
name=f["UNITNAME"], # attribute names → your schema
212-
minAge=f.attribute("MIN_AGE"),
213-
maxAge=f.attribute("MAX_AGE"),
214-
group=f["GROUP"],
215-
)
216-
)
217-
units_df = pd.DataFrame.from_records(units_records)
218-
219-
# relationships_df and contacts_df are domain-specific ─ fill them here
220-
relationships_df = pd.DataFrame(columns=["Index1", "UNITNAME_1", "Index2", "UNITNAME_2"])
221-
contacts_df = pd.DataFrame(columns=["UNITNAME_1", "UNITNAME_2", "length"])
222-
223-
# map_data can be mocked if you only use Age-based sorter
224-
map_data = MapData() # or MapData.from_project(…) / MapData.from_files(…)
225-
226-
feedback.pushInfo(f"Units → {len(units_df)} records")
227-
228-
return units_df, relationships_df, contacts_df, map_data
237+
return __class__()

m2l/processing/provider.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
from .algorithms import (
2020
BasalContactsAlgorithm,
21-
StratigraphySorterAlgorithm,
2221
ThicknessCalculatorAlgorithm,
23-
SamplerAlgorithm
22+
SamplerAlgorithm,
23+
UserDefinedStratigraphyAlgorithm
2424
)
2525

2626
# ############################################################################
@@ -34,9 +34,9 @@ class Map2LoopProvider(QgsProcessingProvider):
3434
def loadAlgorithms(self):
3535
"""Loads all algorithms belonging to this provider."""
3636
self.addAlgorithm(BasalContactsAlgorithm())
37-
self.addAlgorithm(StratigraphySorterAlgorithm())
3837
self.addAlgorithm(ThicknessCalculatorAlgorithm())
3938
self.addAlgorithm(SamplerAlgorithm())
39+
self.addAlgorithm(UserDefinedStratigraphyAlgorithm())
4040

4141
def id(self) -> str:
4242
"""Unique provider id, used for identifying it. This string should be unique, \

requirements/development.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
# Develoment dependencies
22
# -----------------------
33

4-
black
5-
6-
74
isort>=5.13
85
pre-commit>=4,<5

0 commit comments

Comments
 (0)