3131from .vectorLayerWrapper import qgsLayerToGeoDataFrame
3232
3333
34+ def _lookup_colour_ramp (ramp_name ):
35+ """Return the named QGIS colour ramp, or the first available ramp if it is not found."""
36+ style = QgsStyle ().defaultStyle ()
37+ ramp = style .colorRamp (ramp_name ) if ramp_name else None
38+ if ramp is None :
39+ ramp_names = style .colorRampNames ()
40+ if ramp_names :
41+ ramp = style .colorRamp (ramp_names [0 ])
42+ return ramp
43+
44+
3445def _colour_to_qcolor (colour ):
3546 """Convert a stratigraphic unit colour (hex string, colour name, or RGB tuple/array) to a QColor."""
3647 if colour is None :
@@ -619,12 +630,7 @@ def apply_stratigraphic_age_to_layer(self, layer, field_name, ramp_name=None):
619630 )
620631 return False
621632
622- style = QgsStyle ().defaultStyle ()
623- ramp = style .colorRamp (ramp_name ) if ramp_name else None
624- if ramp is None :
625- ramp_names = style .colorRampNames ()
626- if ramp_names :
627- ramp = style .colorRamp (ramp_names [0 ])
633+ ramp = _lookup_colour_ramp (ramp_name )
628634
629635 n = len (unique_values )
630636 ranges = []
@@ -642,6 +648,114 @@ def apply_stratigraphic_age_to_layer(self, layer, field_name, ramp_name=None):
642648 )
643649 return True
644650
651+ def apply_stratigraphic_thickness_to_layer (self , layer , field_name , ramp_name = None ):
652+ """Write each unit's thickness onto a layer and style it with a graduated colour ramp.
653+
654+ Writes a 'strat_thickness' field to ``layer`` holding the thickness
655+ set for the matching unit in the stratigraphic column (matched via
656+ ``field_name``), then applies a graduated renderer over that field.
657+ Features that do not match a unit are left empty.
658+
659+ Parameters
660+ ----------
661+ layer : QgsVectorLayer
662+ The layer to update (e.g. the geological units/geology layer).
663+ field_name : str
664+ Name of the field on ``layer`` holding the stratigraphic unit name.
665+ ramp_name : str, optional
666+ Name of a QGIS colour ramp (from QgsStyle) to use for the
667+ graduated renderer. Falls back to any available ramp if not found.
668+
669+ Returns
670+ -------
671+ bool
672+ True if the field was written and the renderer applied, False otherwise.
673+ """
674+ if layer is None or not field_name :
675+ self .logger (
676+ message = "No layer/unit name field set, cannot apply stratigraphic thickness."
677+ )
678+ return False
679+ if layer .fields ().indexFromName (field_name ) < 0 :
680+ self .logger (message = f"Field '{ field_name } ' not found on layer '{ layer .name ()} '." )
681+ return False
682+
683+ thicknesses = {}
684+ for unit in self ._stratigraphic_column .order :
685+ if unit .element_type != StratigraphicColumnElementType .UNIT :
686+ continue
687+ if unit .thickness is None :
688+ continue
689+ thicknesses [unit .name ] = float (unit .thickness )
690+ if not thicknesses :
691+ self .logger (
692+ message = "Stratigraphic column has no units, cannot apply stratigraphic thickness."
693+ )
694+ return False
695+
696+ thickness_field_name = "strat_thickness"
697+ try :
698+ from qgis .core import QgsField
699+
700+ from loopstructural .gui .compatibility import QVariantCompat
701+
702+ layer .startEditing ()
703+ if layer .fields ().indexFromName (thickness_field_name ) < 0 :
704+ layer .dataProvider ().addAttributes (
705+ [QgsField (thickness_field_name , QVariantCompat .Double )]
706+ )
707+ layer .updateFields ()
708+ thickness_index = layer .fields ().indexFromName (thickness_field_name )
709+ for feature in layer .getFeatures ():
710+ value = feature [field_name ]
711+ unit_name = None if value is None else str (value ).strip ()
712+ layer .changeAttributeValue (
713+ feature .id (), thickness_index , thicknesses .get (unit_name )
714+ )
715+ if not layer .commitChanges ():
716+ raise RuntimeError ("; " .join (layer .commitErrors ()))
717+ except Exception as err :
718+ layer .rollBack ()
719+ self .logger (message = f"Failed to write stratigraphic thickness onto layer: { err } " )
720+ return False
721+
722+ unique_values = set ()
723+ for feature in layer .getFeatures ():
724+ value = feature [thickness_field_name ]
725+ if value is None or (hasattr (value , 'isNull' ) and value .isNull ()):
726+ continue
727+ unique_values .add (float (value ))
728+ unique_values = sorted (unique_values )
729+
730+ if not unique_values :
731+ self .logger (
732+ message = "No features matched a stratigraphic unit, cannot style layer by thickness."
733+ )
734+ return False
735+
736+ ramp = _lookup_colour_ramp (ramp_name )
737+
738+ # One class per thickness value, with the class limits half-way
739+ # between adjacent values so that each value is in only one class.
740+ minimum = unique_values [0 ]
741+ span = unique_values [- 1 ] - minimum
742+ ranges = []
743+ for i , value in enumerate (unique_values ):
744+ lower = value if i == 0 else (unique_values [i - 1 ] + value ) / 2
745+ upper = value if i == len (unique_values ) - 1 else (value + unique_values [i + 1 ]) / 2
746+ symbol = QgsSymbol .defaultSymbol (layer .geometryType ())
747+ if ramp is not None :
748+ symbol .setColor (ramp .color ((value - minimum ) / span if span > 0 else 0 ))
749+ ranges .append (QgsRendererRange (lower , upper , symbol , f"{ value :g} " ))
750+
751+ layer .setRenderer (QgsGraduatedSymbolRenderer (thickness_field_name , ranges ))
752+ layer .triggerRepaint ()
753+ self .logger (
754+ message = f"Applied stratigraphic thickness field '{ thickness_field_name } ' and "
755+ f"graduated styling to layer '{ layer .name ()} '."
756+ )
757+ return True
758+
645759 def get_stratigraphic_unit_names (self ):
646760 """Get the names of the stratigraphic units in the column, youngest first.
647761
0 commit comments