Skip to contents

Description

The soiltestcorr-package also allows users to implement the quadrants analysis approach, also known as the Cate-Nelson analysis. This tutorial is intended to show how to deploy the cate_nelson_1965() function for estimating critical soil test values based on Cate and Nelson (1965). This approach is also known as the “graphical” version of the Cate-Nelson analysis. This method applies an arbitrary fixed value of ry as a target (y-axis) that divides the data into two categories (below & equal or above ry target). In a second stage, it estimates the CSTV (x-axis) as the minimum stv that divides the data into four quadrants (target ry level combined with STV lower or greater than the CSTV) maximizing the number of points under well-classified quadrants (II, stv >= CSTV & ry >= ry target; and IV, stv < CSTV & ry < RY target).

General Instructions

  1. Load your dataframe with soil test value (stv) and relative yield (ry) data.

  2. Specify the following arguments into the function -cate_nelson_1965()-:

(a). data (optional),

(b). stv (soil test value) and ry (relative yield) columns or vectors,

(c). plot TRUE (produces a ggplot as main output) or FALSE (DEFAULT, only produces a list or data.frame),

(d). tidy TRUE (produces a data.frame with results) or FALSE (store results as list),

  1. Run and check results.

  2. Adjust plot as desired.

Tutorial

Suggested packages

# Install if needed 
library(ggplot2) # Plots
library(dplyr) # Data wrangling
library(tidyr) # Data wrangling
library(utils) # Data wrangling
library(data.table) # Mapping
library(purrr) # Mapping

This is a basic example using three different datasets:

Load datasets


# Example 1 dataset
# Fake dataset manually created
data_1 <- data.frame("RY"  = c(65,80,85,88,90,94,93,96,97,95,98,100,99,99,100),
                     "STV" = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15))
  
# Example 2. Native fake dataset from soiltestcorr package

data_2 <- soiltestcorr::data_test


# Example 3. Native dataset from soiltestcorr package, Freitas et al.  (1966), used by Cate & Nelson (1971)
data_3 <- soiltestcorr::freitas1966

Fit cate_nelson_1965()

1. Individual fits

RY target = 90%, replace with your desired value

1.1. tidy = FALSE

It returns a LIST (more efficient for multiple fits at once)


# Using dataframe argument, tidy = FALSE -> return a LIST
fit_1_tidy_false <- 
  soiltestcorr::cate_nelson_1965(data = data_1,
                                 ry = RY,
                                 stv = STV,
                                 target = 90,
                                 tidy = FALSE,
                                 plot = FALSE)
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

utils::head(fit_1_tidy_false)
#> $n
#> [1] 15
#> 
#> $CRYV
#> [1] 90
#> 
#> $CSTV
#> [1] 4.5
#> 
#> $quadrants
#>   q.I q.II q.III q.IV positive negative
#> 1   0   11     0    4       15        0
#> 
#> $X2
#> 
#>  Pearson's Chi-squared test with Yates' continuity correction
#> 
#> data:  data.frame(row.1, row.2)
#> X-squared = 10.322, df = 1, p-value = 0.001314
#> 
#> 
#> $anova
#> Analysis of Variance Table
#> 
#> Response: y
#>           Df Sum Sq Mean Sq F value    Pr(>F)    
#> xgroup     1 843.21  843.21  26.367 0.0001917 ***
#> Residuals 13 415.73   31.98                      
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

1.2. tidy = TRUE

It returns a data.frame (more organized results)


# Using dataframe argument, tidy = FALSE -> return a LIST
fit_1_tidy_false <- 
  soiltestcorr::cate_nelson_1965(data = data_1,
                                 ry = RY,
                                 stv = STV,
                                 target = 90,
                                 tidy = TRUE)
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

utils::head(fit_1_tidy_false)
#>    n CRYV CSTV quadrants.q.I quadrants.q.II quadrants.q.III quadrants.q.IV
#> 1 15   90  4.5             0             11               0              4
#>   quadrants.positive quadrants.negative        R2
#> 1                 15                  0 0.6697782

1.3. Alternative using the vectors

You can call stv and ry vectors using the $.

The tidy argument still applies for controlling the output type


fit_1_vectors_list <-
  soiltestcorr::cate_nelson_1965(ry = data_1$RY,
                                 stv = data_1$STV, 
                                 target=90,
                                 tidy = FALSE)
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

fit_1_vectors_tidy <-
  soiltestcorr::cate_nelson_1965(ry = data_1$RY,
                                 stv = data_1$STV, 
                                 target=90,
                                 tidy = TRUE)
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

1.4. Data 2. Test dataset

fit_2 <-
  soiltestcorr::cate_nelson_1965(data = data_2,
                                 ry = RY,
                                 stv = STV,
                                 target = 90,
                                 tidy = TRUE)

utils::head(fit_2)
#>     n CRYV CSTV quadrants.q.I quadrants.q.II quadrants.q.III quadrants.q.IV
#> 1 137   90   23            11             67               9             50
#>   quadrants.positive quadrants.negative        R2
#> 1                117                 20 0.3936824

1.5. Data 3. Freitas et al. 1966


fit_3 <-
  soiltestcorr::cate_nelson_1965(data = data_3,
                                 ry = RY,
                                 stv = STK,
                                 target = 90,
                                 tidy = TRUE)
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

utils::head(fit_3)
#>    n CRYV CSTV quadrants.q.I quadrants.q.II quadrants.q.III quadrants.q.IV
#> 1 24   90   48             0             12               4              8
#>   quadrants.positive quadrants.negative        R2
#> 1                 20                  4 0.7066536

2. Multiple fits at once

2.1. Using map

Create nested data

Note: the stv column needs to have the same name for all datasets

# 
data.all <- dplyr::bind_rows(data_1, data_2,
                      data_3 %>% dplyr::rename(STV = STK),
                     .id = "id") %>% 
  tidyr::nest(data = c("STV", "RY"))
Fit

# Run multiple examples at once with map()
fit_multiple_map = data.all %>%
  dplyr::mutate(mod_alcc = purrr::map(data, ~ soiltestcorr::cate_nelson_1965(ry = .$RY,
                                                              stv = .$STV,
                                                              target=90,
                                                              tidy = TRUE)))
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

utils::head(fit_multiple_map)
#> # A tibble: 3 × 3
#>   id    data               mod_alcc     
#>   <chr> <list>             <list>       
#> 1 1     <tibble [15 × 2]>  <df [1 × 10]>
#> 2 2     <tibble [137 × 2]> <df [1 × 10]>
#> 3 3     <tibble [24 × 2]>  <df [1 × 10]>

2.1. Using group_map

Alternatively, with group_map, we do not require nested data.

However, it requires to dplyr::bind_rows and add an id column specifying the name of each dataset.

This option return models as lists objects.


fit_multiple_group_map <- 
  data.all %>% tidyr::unnest(data) %>% 
  #dplyr::bind_rows(data_1, data_2, .id = "id") %>% 
  dplyr::group_by(id) %>% 
  dplyr::group_map(~ soiltestcorr::cate_nelson_1965(data = ., 
                                     ry = RY,
                                     stv = STV, 
                                     target = 90, 
                                     tidy = TRUE))
#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

#> Warning in stats::chisq.test(data.frame(row.1, row.2)): Chi-squared
#> approximation may be incorrect

utils::head(fit_multiple_group_map)
#> [[1]]
#>    n CRYV CSTV quadrants.q.I quadrants.q.II quadrants.q.III quadrants.q.IV
#> 1 15   90  4.5             0             11               0              4
#>   quadrants.positive quadrants.negative        R2
#> 1                 15                  0 0.6697782
#> 
#> [[2]]
#>     n CRYV CSTV quadrants.q.I quadrants.q.II quadrants.q.III quadrants.q.IV
#> 1 137   90   23            11             67               9             50
#>   quadrants.positive quadrants.negative        R2
#> 1                117                 20 0.3936824
#> 
#> [[3]]
#>    n CRYV CSTV quadrants.q.I quadrants.q.II quadrants.q.III quadrants.q.IV
#> 1 24   90   48             0             12               4              8
#>   quadrants.positive quadrants.negative        R2
#> 1                 20                  4 0.7066536

3. Plots

3.1. Calibration Curve

We can generate a ggplot with the same mod_alcc() function.

We just need to specify the argument plot = TRUE.


soiltestcorr::cate_nelson_1965(data = data_1, 
                       ry = RY, 
                       stv = STV, 
                       target=90, 
                       plot = TRUE)


soiltestcorr::cate_nelson_1965(data = data_2, 
                       ry = RY, 
                       stv = STV, 
                       target=90, 
                       plot = TRUE)


soiltestcorr::cate_nelson_1965(data = data_3, 
                       ry = RY, 
                       stv = STK, 
                       target=90, 
                       plot = TRUE)

References

Cate, R.B. Jr., and Nelson, L.A., 1965. A rapid method for correlation of soil test analysis with plant response data. North Carolina Agric. Exp. Stn., International soil Testing Series Bull. No. 1.