The PSU2024 field CSV (data/PSU2024.csv) provides
per-plot phenotype data with design columns REP,
IBLOCK, P_SQUARE, ROW,
COLUMN, but no absolute field X/Y
coordinates. SpATS spatial correction needs X/Y on a single
continuous grid covering all plots.
This notebook documents how those coordinates were inferred from the
data and the in-field knowledge that the smallest plot ID (RS)
is at the bottom-left of the field and the maximum at the top-right,
with -P treatment on the left and +P on the right. The
resulting offset table is what
Corrected_phenotype_analysis_PSU2024.Rmd uses in its X/Y
derivation.
dat <- read_csv(here("data", "PSU2024.csv"), show_col_types = FALSE) %>%
mutate(P_LEVEL = factor(P_LEVEL, levels = c("LOW_P", "HIGH_P")))
cat("rows:", nrow(dat), "\n")
## rows: 960
cat("ROW range: ", range(dat$ROW), "\n")
## ROW range: 1 10
cat("COLUMN range: ", range(dat$COLUMN), "\n")
## COLUMN range: 1 24
cat("REP levels: ", paste(sort(unique(dat$REP)), collapse = ", "), "\n")
## REP levels: 1, 2, 3, 4, 5
cat("IBLOCK levels:", paste(sort(unique(dat$IBLOCK)), collapse = ", "), "\n")
## IBLOCK levels: 1, 2, 3, 4, 5, 6, 7, 8
cat("P_SQUARE: ", paste(sort(unique(dat$P_SQUARE)), collapse = ", "), "\n")
## P_SQUARE: 1, 2, 3, 4
cat("P_LEVEL: ", paste(levels(dat$P_LEVEL), collapse = ", "), "\n")
## P_LEVEL: LOW_P, HIGH_P
cat("n GENOTYPE: ", length(unique(dat$GENOTYPE)), "\n")
## n GENOTYPE: 46
cat("RS range: ", range(dat$RS), "\n")
## RS range: 2001 2960
dat %>% count(REP, P_SQUARE, P_LEVEL) %>% print(n = 30)
## # A tibble: 20 × 4
## REP P_SQUARE P_LEVEL n
## <dbl> <dbl> <fct> <int>
## 1 1 1 LOW_P 48
## 2 1 2 HIGH_P 48
## 3 1 3 LOW_P 48
## 4 1 4 HIGH_P 48
## 5 2 1 LOW_P 48
## 6 2 2 HIGH_P 48
## 7 2 3 LOW_P 48
## 8 2 4 HIGH_P 48
## 9 3 1 LOW_P 48
## 10 3 2 HIGH_P 48
## 11 3 3 LOW_P 48
## 12 3 4 HIGH_P 48
## 13 4 1 LOW_P 48
## 14 4 2 HIGH_P 48
## 15 4 3 LOW_P 48
## 16 4 4 HIGH_P 48
## 17 5 1 LOW_P 48
## 18 5 2 HIGH_P 48
## 19 5 3 LOW_P 48
## 20 5 4 HIGH_P 48
5 REPs × 4 P_SQUAREs × 48 plots = 960 plots. P_SQUAREs 1 and 3 are LOW_P, P_SQUAREs 2 and 4 are HIGH_P.
If ROW × COLUMN were global field
coordinates we’d expect one plot per cell. Counting how many plots share
each (ROW, COLUMN):
dat %>% count(ROW, COLUMN) %>%
count(n, name = "cells_with_this_count")
## # A tibble: 1 × 2
## n cells_with_this_count
## <int> <int>
## 1 4 240
dat %>% count(REP, P_SQUARE, ROW, COLUMN) %>%
count(n, name = "cells_with_this_count")
## # A tibble: 1 × 2
## n cells_with_this_count
## <int> <int>
## 1 1 960
Each (ROW, COLUMN) is shared by 4 plots — one per
P_SQUARE — but (REP, P_SQUARE, ROW, COLUMN) is a unique
identifier. So ROW and COLUMN restart
inside each P_SQUARE, and P_SQUARE is an independent block
dimension not captured by the spatial coords alone.
dat %>% group_by(P_LEVEL) %>%
summarise(n = n(), RS_min = min(RS), RS_max = max(RS),
ID_min = min(ID), ID_max = max(ID))
## # A tibble: 2 × 6
## P_LEVEL n RS_min RS_max ID_min ID_max
## <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 LOW_P 480 2001 2720 1 720
## 2 HIGH_P 480 2241 2960 241 960
dat %>% group_by(P_SQUARE, P_LEVEL) %>%
summarise(n = n(), RS_min = min(RS), RS_max = max(RS),
ID_min = min(ID), ID_max = max(ID), .groups = "drop")
## # A tibble: 4 × 7
## P_SQUARE P_LEVEL n RS_min RS_max ID_min ID_max
## <dbl> <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 LOW_P 240 2001 2240 1 240
## 2 2 HIGH_P 240 2241 2480 241 480
## 3 3 LOW_P 240 2481 2720 481 720
## 4 4 HIGH_P 240 2721 2960 721 960
RS is contiguous within each P_SQUARE — no interleaving. P_SQ 1 = LOW_P (2001-2240), P_SQ 2 = HIGH_P (2241-2480), P_SQ 3 = LOW_P (2481-2720), P_SQ 4 = HIGH_P (2721-2960). The ID-numbering scheme labels the P_SQUAREs but does not by itself determine their physical arrangement in the field.
PSU2022 used a comparable 4-square design with thousands-digit encoding of P treatment. Same pattern — two LowP blocks and two HighP blocks, each spanning 192 plots (16 IBLOCK × 12 plots):
psu2022 <- read_csv(here("data", "22_NCS_PSU_LANGEBIO_FIELDS_PSU_P_field.csv"),
show_col_types = FALSE) %>%
rename(plot_id = `P22-`)
psu2022 %>% group_by(Treatment) %>%
summarise(n = n(), id_min = min(plot_id), id_max = max(plot_id))
## # A tibble: 2 × 4
## Treatment n id_min id_max
## <chr> <int> <dbl> <dbl>
## 1 HighP 384 2001 4192
## 2 LowP 384 1001 3192
PSU2022 LowP plots cluster in 1xxx + 3xxx,
HighP plots in 2xxx + 4xxx — the same
alternating-block convention. Physical orientation (-P left / +P right)
was confirmed by field observation.
Combining:
ROW (1-10) and COLUMN (1-24) are local
within each 240-plot P_SQUARE.Gives a 2×2 layout:
top | P_SQ 3 (LowP) | P_SQ 4 (HighP) | RS 2960 → top-right
bottom | P_SQ 1 (LowP) | P_SQ 2 (HighP) | RS 2001 → bottom-left
ROW 1-10, COL 1-24 ROW 1-10, COL 1-24
Assembled field = 20 rows tall × 48 columns wide.
n_col_psq <- max(dat$COLUMN) # 24
n_row_psq <- max(dat$ROW) # 10
psq_x_offset <- c(`1` = 0L, `3` = 0L,
`2` = n_col_psq, `4` = n_col_psq)
psq_y_offset <- c(`1` = 0L, `2` = 0L,
`3` = n_row_psq, `4` = n_row_psq)
dat <- dat %>%
mutate(X = psq_x_offset[as.character(P_SQUARE)] + COLUMN,
Y = psq_y_offset[as.character(P_SQUARE)] + ROW)
dat %>% group_by(P_SQUARE, P_LEVEL) %>%
summarise(X_range = paste(range(X), collapse = "-"),
Y_range = paste(range(Y), collapse = "-"),
.groups = "drop")
## # A tibble: 4 × 4
## P_SQUARE P_LEVEL X_range Y_range
## <dbl> <fct> <chr> <chr>
## 1 1 LOW_P 1-24 1-10
## 2 2 HIGH_P 25-48 1-10
## 3 3 LOW_P 1-24 11-20
## 4 4 HIGH_P 25-48 11-20
This is the exact offset table copied into
Corrected_phenotype_analysis_PSU2024.Rmd §2.
p_lvl <- ggplot(dat, aes(x = X, y = Y, fill = P_LEVEL)) +
geom_tile(color = "white", linewidth = 0.15) +
scale_fill_manual(values = c("LOW_P" = "#d95f02", "HIGH_P" = "#1b9e77")) +
scale_y_continuous(breaks = seq(1, 20, 2)) +
coord_equal() +
labs(title = "PA2024 field — assembled 2×2 layout, colored by P_LEVEL",
subtitle = "RS 2001 bottom-left → RS 2960 top-right; -P on left, +P on right",
x = "field X (assembled, COL 1-48)", y = "field row (1-20)",
fill = "P level") +
theme_minimal(base_size = 11) +
theme(panel.grid = element_blank())
ggsave(file.path(paths$figures, "PSU2024_layout_by_P_LEVEL.png"),
p_lvl, width = 9, height = 6, dpi = 150)
p_lvl
p_sq <- ggplot(dat, aes(x = X, y = Y, fill = factor(P_SQUARE))) +
geom_tile(color = "white", linewidth = 0.15) +
scale_y_continuous(breaks = seq(1, 20, 2)) +
coord_equal() +
labs(title = "PA2024 field — colored by P_SQUARE",
x = "field X (assembled)", y = "field row",
fill = "P_SQUARE") +
theme_minimal(base_size = 11) +
theme(panel.grid = element_blank())
ggsave(file.path(paths$figures, "PSU2024_layout_by_P_SQUARE.png"),
p_sq, width = 9, height = 6, dpi = 150)
p_sq
p_rep <- ggplot(dat, aes(x = X, y = Y, fill = factor(REP))) +
geom_tile(color = "white", linewidth = 0.15) +
scale_y_continuous(breaks = seq(1, 20, 2)) +
coord_equal() +
labs(title = "PA2024 field — colored by REP",
x = "field X (assembled)", y = "field row",
fill = "REP") +
theme_minimal(base_size = 11) +
theme(panel.grid = element_blank())
ggsave(file.path(paths$figures, "PSU2024_layout_by_REP.png"),
p_rep, width = 9, height = 6, dpi = 150)
p_rep
Wide-format CSV: rows = field Y (sorted descending so the top of the spreadsheet matches the top of the field), columns = field X (1-48). Each cell holds the RS plot ID at that (X, Y) position.
rs_grid <- dat %>%
select(X, Y, RS) %>%
arrange(desc(Y), X) %>%
pivot_wider(id_cols = Y, names_from = X, values_from = RS,
names_prefix = "X") %>%
arrange(desc(Y))
out_csv <- file.path(paths$intermediate, "PSU2024_layout_RS_grid.csv")
write_csv(rs_grid, out_csv)
cat("wrote", out_csv, "\n")
## wrote /Users/fvrodriguez/Library/CloudStorage/GoogleDrive-frodrig4@ncsu.edu/My Drive/repos/inv4m/results/inversion_paper/intermediate/PSU2024_layout_RS_grid.csv
knitr::kable(rs_grid,
caption = "RS plot ID at each (X, Y); Y descending so top row = top of field.")
| Y | X1 | X2 | X3 | X4 | X5 | X6 | X7 | X8 | X9 | X10 | X11 | X12 | X13 | X14 | X15 | X16 | X17 | X18 | X19 | X20 | X21 | X22 | X23 | X24 | X25 | X26 | X27 | X28 | X29 | X30 | X31 | X32 | X33 | X34 | X35 | X36 | X37 | X38 | X39 | X40 | X41 | X42 | X43 | X44 | X45 | X46 | X47 | X48 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 20 | 2720 | 2719 | 2718 | 2717 | 2716 | 2715 | 2714 | 2713 | 2712 | 2711 | 2710 | 2709 | 2708 | 2707 | 2706 | 2705 | 2704 | 2703 | 2702 | 2701 | 2700 | 2699 | 2698 | 2697 | 2960 | 2959 | 2958 | 2957 | 2956 | 2955 | 2954 | 2953 | 2952 | 2951 | 2950 | 2949 | 2948 | 2947 | 2946 | 2945 | 2944 | 2943 | 2942 | 2941 | 2940 | 2939 | 2938 | 2937 |
| 19 | 2673 | 2674 | 2675 | 2676 | 2677 | 2678 | 2679 | 2680 | 2681 | 2682 | 2683 | 2684 | 2685 | 2686 | 2687 | 2688 | 2689 | 2690 | 2691 | 2692 | 2693 | 2694 | 2695 | 2696 | 2913 | 2914 | 2915 | 2916 | 2917 | 2918 | 2919 | 2920 | 2921 | 2922 | 2923 | 2924 | 2925 | 2926 | 2927 | 2928 | 2929 | 2930 | 2931 | 2932 | 2933 | 2934 | 2935 | 2936 |
| 18 | 2672 | 2671 | 2670 | 2669 | 2668 | 2667 | 2666 | 2665 | 2664 | 2663 | 2662 | 2661 | 2660 | 2659 | 2658 | 2657 | 2656 | 2655 | 2654 | 2653 | 2652 | 2651 | 2650 | 2649 | 2912 | 2911 | 2910 | 2909 | 2908 | 2907 | 2906 | 2905 | 2904 | 2903 | 2902 | 2901 | 2900 | 2899 | 2898 | 2897 | 2896 | 2895 | 2894 | 2893 | 2892 | 2891 | 2890 | 2889 |
| 17 | 2625 | 2626 | 2627 | 2628 | 2629 | 2630 | 2631 | 2632 | 2633 | 2634 | 2635 | 2636 | 2637 | 2638 | 2639 | 2640 | 2641 | 2642 | 2643 | 2644 | 2645 | 2646 | 2647 | 2648 | 2865 | 2866 | 2867 | 2868 | 2869 | 2870 | 2871 | 2872 | 2873 | 2874 | 2875 | 2876 | 2877 | 2878 | 2879 | 2880 | 2881 | 2882 | 2883 | 2884 | 2885 | 2886 | 2887 | 2888 |
| 16 | 2624 | 2623 | 2622 | 2621 | 2620 | 2619 | 2618 | 2617 | 2616 | 2615 | 2614 | 2613 | 2612 | 2611 | 2610 | 2609 | 2608 | 2607 | 2606 | 2605 | 2604 | 2603 | 2602 | 2601 | 2864 | 2863 | 2862 | 2861 | 2860 | 2859 | 2858 | 2857 | 2856 | 2855 | 2854 | 2853 | 2852 | 2851 | 2850 | 2849 | 2848 | 2847 | 2846 | 2845 | 2844 | 2843 | 2842 | 2841 |
| 15 | 2577 | 2578 | 2579 | 2580 | 2581 | 2582 | 2583 | 2584 | 2585 | 2586 | 2587 | 2588 | 2589 | 2590 | 2591 | 2592 | 2593 | 2594 | 2595 | 2596 | 2597 | 2598 | 2599 | 2600 | 2817 | 2818 | 2819 | 2820 | 2821 | 2822 | 2823 | 2824 | 2825 | 2826 | 2827 | 2828 | 2829 | 2830 | 2831 | 2832 | 2833 | 2834 | 2835 | 2836 | 2837 | 2838 | 2839 | 2840 |
| 14 | 2576 | 2575 | 2574 | 2573 | 2572 | 2571 | 2570 | 2569 | 2568 | 2567 | 2566 | 2565 | 2564 | 2563 | 2562 | 2561 | 2560 | 2559 | 2558 | 2557 | 2556 | 2555 | 2554 | 2553 | 2816 | 2815 | 2814 | 2813 | 2812 | 2811 | 2810 | 2809 | 2808 | 2807 | 2806 | 2805 | 2804 | 2803 | 2802 | 2801 | 2800 | 2799 | 2798 | 2797 | 2796 | 2795 | 2794 | 2793 |
| 13 | 2529 | 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 | 2537 | 2538 | 2539 | 2540 | 2541 | 2542 | 2543 | 2544 | 2545 | 2546 | 2547 | 2548 | 2549 | 2550 | 2551 | 2552 | 2769 | 2770 | 2771 | 2772 | 2773 | 2774 | 2775 | 2776 | 2777 | 2778 | 2779 | 2780 | 2781 | 2782 | 2783 | 2784 | 2785 | 2786 | 2787 | 2788 | 2789 | 2790 | 2791 | 2792 |
| 12 | 2528 | 2527 | 2526 | 2525 | 2524 | 2523 | 2522 | 2521 | 2520 | 2519 | 2518 | 2517 | 2516 | 2515 | 2514 | 2513 | 2512 | 2511 | 2510 | 2509 | 2508 | 2507 | 2506 | 2505 | 2768 | 2767 | 2766 | 2765 | 2764 | 2763 | 2762 | 2761 | 2760 | 2759 | 2758 | 2757 | 2756 | 2755 | 2754 | 2753 | 2752 | 2751 | 2750 | 2749 | 2748 | 2747 | 2746 | 2745 |
| 11 | 2481 | 2482 | 2483 | 2484 | 2485 | 2486 | 2487 | 2488 | 2489 | 2490 | 2491 | 2492 | 2493 | 2494 | 2495 | 2496 | 2497 | 2498 | 2499 | 2500 | 2501 | 2502 | 2503 | 2504 | 2721 | 2722 | 2723 | 2724 | 2725 | 2726 | 2727 | 2728 | 2729 | 2730 | 2731 | 2732 | 2733 | 2734 | 2735 | 2736 | 2737 | 2738 | 2739 | 2740 | 2741 | 2742 | 2743 | 2744 |
| 10 | 2240 | 2239 | 2238 | 2237 | 2236 | 2235 | 2234 | 2233 | 2232 | 2231 | 2230 | 2229 | 2228 | 2227 | 2226 | 2225 | 2224 | 2223 | 2222 | 2221 | 2220 | 2219 | 2218 | 2217 | 2480 | 2479 | 2478 | 2477 | 2476 | 2475 | 2474 | 2473 | 2472 | 2471 | 2470 | 2469 | 2468 | 2467 | 2466 | 2465 | 2464 | 2463 | 2462 | 2461 | 2460 | 2459 | 2458 | 2457 |
| 9 | 2193 | 2194 | 2195 | 2196 | 2197 | 2198 | 2199 | 2200 | 2201 | 2202 | 2203 | 2204 | 2205 | 2206 | 2207 | 2208 | 2209 | 2210 | 2211 | 2212 | 2213 | 2214 | 2215 | 2216 | 2433 | 2434 | 2435 | 2436 | 2437 | 2438 | 2439 | 2440 | 2441 | 2442 | 2443 | 2444 | 2445 | 2446 | 2447 | 2448 | 2449 | 2450 | 2451 | 2452 | 2453 | 2454 | 2455 | 2456 |
| 8 | 2192 | 2191 | 2190 | 2189 | 2188 | 2187 | 2186 | 2185 | 2184 | 2183 | 2182 | 2181 | 2180 | 2179 | 2178 | 2177 | 2176 | 2175 | 2174 | 2173 | 2172 | 2171 | 2170 | 2169 | 2432 | 2431 | 2430 | 2429 | 2428 | 2427 | 2426 | 2425 | 2424 | 2423 | 2422 | 2421 | 2420 | 2419 | 2418 | 2417 | 2416 | 2415 | 2414 | 2413 | 2412 | 2411 | 2410 | 2409 |
| 7 | 2145 | 2146 | 2147 | 2148 | 2149 | 2150 | 2151 | 2152 | 2153 | 2154 | 2155 | 2156 | 2157 | 2158 | 2159 | 2160 | 2161 | 2162 | 2163 | 2164 | 2165 | 2166 | 2167 | 2168 | 2385 | 2386 | 2387 | 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 | 2400 | 2401 | 2402 | 2403 | 2404 | 2405 | 2406 | 2407 | 2408 |
| 6 | 2144 | 2143 | 2142 | 2141 | 2140 | 2139 | 2138 | 2137 | 2136 | 2135 | 2134 | 2133 | 2132 | 2131 | 2130 | 2129 | 2128 | 2127 | 2126 | 2125 | 2124 | 2123 | 2122 | 2121 | 2384 | 2383 | 2382 | 2381 | 2380 | 2379 | 2378 | 2377 | 2376 | 2375 | 2374 | 2373 | 2372 | 2371 | 2370 | 2369 | 2368 | 2367 | 2366 | 2365 | 2364 | 2363 | 2362 | 2361 |
| 5 | 2097 | 2098 | 2099 | 2100 | 2101 | 2102 | 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 2111 | 2112 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2337 | 2338 | 2339 | 2340 | 2341 | 2342 | 2343 | 2344 | 2345 | 2346 | 2347 | 2348 | 2349 | 2350 | 2351 | 2352 | 2353 | 2354 | 2355 | 2356 | 2357 | 2358 | 2359 | 2360 |
| 4 | 2096 | 2095 | 2094 | 2093 | 2092 | 2091 | 2090 | 2089 | 2088 | 2087 | 2086 | 2085 | 2084 | 2083 | 2082 | 2081 | 2080 | 2079 | 2078 | 2077 | 2076 | 2075 | 2074 | 2073 | 2336 | 2335 | 2334 | 2333 | 2332 | 2331 | 2330 | 2329 | 2328 | 2327 | 2326 | 2325 | 2324 | 2323 | 2322 | 2321 | 2320 | 2319 | 2318 | 2317 | 2316 | 2315 | 2314 | 2313 |
| 3 | 2049 | 2050 | 2051 | 2052 | 2053 | 2054 | 2055 | 2056 | 2057 | 2058 | 2059 | 2060 | 2061 | 2062 | 2063 | 2064 | 2065 | 2066 | 2067 | 2068 | 2069 | 2070 | 2071 | 2072 | 2289 | 2290 | 2291 | 2292 | 2293 | 2294 | 2295 | 2296 | 2297 | 2298 | 2299 | 2300 | 2301 | 2302 | 2303 | 2304 | 2305 | 2306 | 2307 | 2308 | 2309 | 2310 | 2311 | 2312 |
| 2 | 2048 | 2047 | 2046 | 2045 | 2044 | 2043 | 2042 | 2041 | 2040 | 2039 | 2038 | 2037 | 2036 | 2035 | 2034 | 2033 | 2032 | 2031 | 2030 | 2029 | 2028 | 2027 | 2026 | 2025 | 2288 | 2287 | 2286 | 2285 | 2284 | 2283 | 2282 | 2281 | 2280 | 2279 | 2278 | 2277 | 2276 | 2275 | 2274 | 2273 | 2272 | 2271 | 2270 | 2269 | 2268 | 2267 | 2266 | 2265 |
| 1 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2241 | 2242 | 2243 | 2244 | 2245 | 2246 | 2247 | 2248 | 2249 | 2250 | 2251 | 2252 | 2253 | 2254 | 2255 | 2256 | 2257 | 2258 | 2259 | 2260 | 2261 | 2262 | 2263 | 2264 |
This layout interpretation rests on two pieces of in-field knowledge:
If either is wrong, the offset table at §7 needs to change. Specifically:
The downstream analysis
(Corrected_phenotype_analysis_PSU2024.Rmd) uses these X/Y
as the SpATS spatial coords with no further assumptions about plot
positions, so a wrong layout would manifest as a poor SpATS surface fit
(and visibly weird spatial residual plots).