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

1# SPDX-FileCopyrightText: 2026 German Aerospace Center (DLR) 

2# SPDX-License-Identifier: GPL-3.0-or-later 

3 

4"""Post-processing utility for blob experiment CSV files. 

5 

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. 

10 

11Usage 

12----- 

13 # Write to a new file (safe default): 

14 python for_blob_formatting.py --input 128_F9_blob_radius8.csv 

15 

16 # Specify a custom output path: 

17 python for_blob_formatting.py --input 128_F9_blob_radius8.csv --output cleaned.csv 

18 

19 # Overwrite the input file in-place (use with caution): 

20 python for_blob_formatting.py --input 128_F9_blob_radius8.csv --inplace 

21""" 

22 

23import argparse 

24import sys 

25 

26import pandas as pd 

27 

28 

29def extract_first_float(value: str | float) -> float | None: 

30 """Extract a float from a value that may be a tuple-like string. 

31 

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. 

35 

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 

47 

48 

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() 

74 

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) 

81 

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" 

89 

90 df = pd.read_csv(args.input) 

91 

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) 

98 

99 df["intensity"] = df["intensity"].apply(extract_first_float) 

100 

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 ) 

107 

108 df.to_csv(output_path, index=False) 

109 print(f"Done. Formatted CSV saved to: {output_path}") 

110 

111 

112if __name__ == "__main__": 

113 main()