File size: 1,506 Bytes
3ecb175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
affeea4
 
 
 
 
 
3ecb175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""QC filters applied to the per-tuber morphometrics dataframe.

Three steps:
- Drop ADC plot images whose ROI cropping removed substantial tuber area.
- Derive the PCA-based axis ratio from eccentricity.
- Filter out tubers with axis_ratio_pca above the pooled 99.5th percentile.
"""

from __future__ import annotations

import numpy as np
import pandas as pd

# ADC plot images dropped because the cropping step removed substantial
# tuber area. Values are the raw "Plot" column (image_id[-8:]).
ADC_QC_DROP_PLOTS: tuple[str, ...] = (
    "5_ADC116",
    "5_ADC131",
    "5_ADC141",
    "5_ADC129",
    "5_ADC105",
    "5_ADC205",
)

AR_PCA_FILTER_QUANTILE: float = 0.995


def drop_qc_plots(
    df: pd.DataFrame,
    drop_plots: tuple[str, ...] = ADC_QC_DROP_PLOTS,
    plot_col: str = "Plot",
) -> pd.DataFrame:
    """Drop plots listed in drop_plots from the per-tuber dataframe."""
    return df[~df[plot_col].isin(drop_plots)].copy()


def derive_axis_ratio_pca(df: pd.DataFrame) -> pd.DataFrame:
    """Add axis_ratio_pca = 1 / sqrt(1 - eccentricity^2)."""
    df = df.copy()
    ecc = np.clip(df["eccentricity"], 0, 0.999999)
    df["axis_ratio_pca"] = 1.0 / np.sqrt(1.0 - ecc**2)
    return df


def filter_axis_ratio(
    df: pd.DataFrame,
    quantile: float = AR_PCA_FILTER_QUANTILE,
) -> pd.DataFrame:
    """Keep tubers with axis_ratio_pca at or below the pooled quantile threshold."""
    upper = df["axis_ratio_pca"].quantile(quantile)
    return df[df["axis_ratio_pca"] <= upper].copy()