Coverage for src/crackmnist_eccv/for_blob_formatting.py: 28%
35 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-10-19 08:00 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-10-19 08:00 +0000
1# SPDX-FileCopyrightText: 2026 German Aerospace Center (DLR)
2# SPDX-License-Identifier: GPL-3.0-or-later
4"""Post-processing utility for blob experiment CSV files.
6When blob pollution intensities are stored as tuple-like strings
7(e.g. "(0.1, 0.2)"), this script extracts the first float value from
8the 'intensity' column so that the CSV can be used directly by
9plot_seaborn_automated.py.
11Usage
12-----
13 # Write to a new file (safe default):
14 python for_blob_formatting.py --input 128_F9_blob_radius8.csv
16 # Specify a custom output path:
17 python for_blob_formatting.py --input 128_F9_blob_radius8.csv --output cleaned.csv
19 # Overwrite the input file in-place (use with caution):
20 python for_blob_formatting.py --input 128_F9_blob_radius8.csv --inplace
21"""
23import argparse
24import sys
26import pandas as pd
29def extract_first_float(value: str | float) -> float | None:
30 """Extract a float from a value that may be a tuple-like string.
32 Args:
33 value: If a string starting with '(', the first comma-separated element
34 is parsed. Otherwise the value is cast directly to float.
36 Returns:
37 -------
38 float or None
39 Parsed float, or None if parsing fails.
40 """
41 try:
42 if isinstance(value, str) and value.startswith("("):
43 return float(value.split(",")[0].strip("() "))
44 return float(value)
45 except (ValueError, AttributeError):
46 return None
49def main() -> None:
50 """Parse arguments, load CSV, extract float intensities, and save."""
51 parser = argparse.ArgumentParser(
52 description=(
53 "Extract first float from tuple-like 'intensity' values in a blob CSV file."
54 )
55 )
56 parser.add_argument(
57 "--input",
58 "-i",
59 required=True,
60 help="Path to the input CSV file (e.g. 128_F9_blob_radius8.csv).",
61 )
62 parser.add_argument(
63 "--output",
64 "-o",
65 default=None,
66 help=("Path for the output CSV file. Defaults to '<input_stem>_formatted.csv'."),
67 )
68 parser.add_argument(
69 "--inplace",
70 action="store_true",
71 help="Overwrite the input file. Cannot be combined with --output.",
72 )
73 args = parser.parse_args()
75 if args.inplace and args.output:
76 print(
77 "Error: --inplace and --output cannot be used together.",
78 file=sys.stderr,
79 )
80 sys.exit(1)
82 if args.inplace:
83 output_path = args.input
84 elif args.output:
85 output_path = args.output
86 else:
87 stem = args.input.removesuffix(".csv")
88 output_path = f"{stem}_formatted.csv"
90 df = pd.read_csv(args.input)
92 if "intensity" not in df.columns:
93 print(
94 f"Error: no 'intensity' column found in '{args.input}'.",
95 file=sys.stderr,
96 )
97 sys.exit(1)
99 df["intensity"] = df["intensity"].apply(extract_first_float)
101 n_failed = df["intensity"].isna().sum()
102 if n_failed > 0:
103 print(
104 f"Warning: {n_failed} row(s) could not be parsed and were set to NaN.",
105 file=sys.stderr,
106 )
108 df.to_csv(output_path, index=False)
109 print(f"Done. Formatted CSV saved to: {output_path}")
112if __name__ == "__main__":
113 main()