From a22496ddf559e462cd328e10acf1495286f77e82 Mon Sep 17 00:00:00 2001 From: Jonathan Maynard Date: Tue, 20 Jan 2026 11:07:37 -0800 Subject: [PATCH 1/2] fix: Fix getTexture function to match legacy gettt logic - Return None instead of 'Unknown' for invalid/NaN inputs - Fix Loamy sand condition to use silt + 2.0*clay < 30 - Add missing Silty clay loam texture class - Fix Silty clay condition to require silt >= 40% - Fix Clay condition to require sand <= 45% and silt < 40% - Ensures texture classification matches USDA standards --- soil_id/utils.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/soil_id/utils.py b/soil_id/utils.py index 54a95a1..a3050d0 100644 --- a/soil_id/utils.py +++ b/soil_id/utils.py @@ -110,6 +110,7 @@ def silt_calc(row): def getTexture(row=None, sand=None, silt=None, clay=None): """ Classify soil texture based on sand, silt, and clay proportions. + Matches the legacy gettt function logic. Parameters: - row (dict): Dictionary-like object with 'sandtotal_r', 'silttotal_r', 'claytotal_r' keys. @@ -118,7 +119,7 @@ def getTexture(row=None, sand=None, silt=None, clay=None): - clay (float): Percentage of clay. Returns: - - str: Soil texture classification. + - str: Soil texture classification, or None if any input is NaN. """ # Handle missing inputs: if not provided individually, try to get from row. @@ -127,29 +128,31 @@ def getTexture(row=None, sand=None, silt=None, clay=None): sand = row.get("sandtotal_r", np.nan) silt = row.get("silttotal_r", np.nan) clay = row.get("claytotal_r", np.nan) - - # Replace any NaN with 0 for the calculation. - sand = np.nan_to_num(sand, nan=0) - silt = np.nan_to_num(silt, nan=0) - clay = np.nan_to_num(clay, nan=0) + + # Return None if any value is NaN (matches legacy behavior) + if np.isnan(sand) or np.isnan(silt) or np.isnan(clay): + return None # Calculate derived values. silt_clay = silt + 1.5 * clay silt_2x_clay = silt + 2.0 * clay # Define conditions and corresponding texture classifications. + # These match the legacy gettt function exactly conditions = [ silt_clay < 15, - (silt_clay >= 15) & (silt_clay < 30), - (((7 <= clay) & (clay <= 20)) & (sand > 52)) + (silt_clay >= 15) & (silt_2x_clay < 30), # Fixed: was using silt_clay for both + (((clay >= 7) & (clay <= 20)) & (sand > 52) & (silt_2x_clay >= 30)) | ((clay < 7) & (silt < 50) & (silt_2x_clay >= 30)), - (7 <= clay) & (clay <= 27) & (28 <= silt) & (silt < 50) & (sand <= 52), - (silt >= 50) & (((12 <= clay) & (clay < 27)) | ((silt < 80) & (clay < 12))), + (clay >= 7) & (clay <= 27) & (silt >= 28) & (silt < 50) & (sand <= 52), + ((silt >= 50) & (clay >= 12) & (clay < 27)) | ((silt >= 50) & (silt < 80) & (clay < 12)), (silt >= 80) & (clay < 12), - (20 <= clay) & (clay < 35) & (silt < 28) & (sand > 45), - (27 <= clay) & (clay < 40) & (sand <= 45) & (sand > 20), + (clay >= 20) & (clay < 35) & (silt < 28) & (sand > 45), + (clay >= 27) & (clay < 40) & (sand > 20) & (sand <= 45), + (clay >= 27) & (clay < 40) & (sand <= 20), (clay >= 35) & (sand >= 45), - (clay >= 40) & (silt >= 40) & (sand <= 45), + (clay >= 40) & (silt >= 40), + (clay >= 40) & (sand <= 45) & (silt < 40), ] choices = [ @@ -161,12 +164,14 @@ def getTexture(row=None, sand=None, silt=None, clay=None): "Silt", "Sandy clay loam", "Clay loam", + "Silty clay loam", "Sandy clay", + "Silty clay", "Clay", ] # Compute the texture classification. - result = np.select(conditions, choices, default="Unknown") + result = np.select(conditions, choices, default=None) # Ensure that a plain Python string is returned. if isinstance(result, np.ndarray): From 3efabdd9c83833da232566751a05e65ec1db59ad Mon Sep 17 00:00:00 2001 From: Jonathan Maynard Date: Tue, 20 Jan 2026 15:45:52 -0800 Subject: [PATCH 2/2] Clean up formatting in utils.py Removed unnecessary blank line in the get soil components function. --- soil_id/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soil_id/utils.py b/soil_id/utils.py index a3050d0..8cf1582 100644 --- a/soil_id/utils.py +++ b/soil_id/utils.py @@ -128,7 +128,7 @@ def getTexture(row=None, sand=None, silt=None, clay=None): sand = row.get("sandtotal_r", np.nan) silt = row.get("silttotal_r", np.nan) clay = row.get("claytotal_r", np.nan) - + # Return None if any value is NaN (matches legacy behavior) if np.isnan(sand) or np.isnan(silt) or np.isnan(clay): return None