Ansaribinhyder commited on
Commit
33d5431
·
1 Parent(s): 0f4c3d4

Enhanced SPC Control

Browse files
Files changed (2) hide show
  1. .gitignore +1 -0
  2. SPC_System/spc_engine.py +107 -130
.gitignore CHANGED
@@ -4,3 +4,4 @@ test.ipynb
4
  *.xlsx
5
  *.json
6
  charts/*.png
 
 
4
  *.xlsx
5
  *.json
6
  charts/*.png
7
+ charts_compare/*.png
SPC_System/spc_engine.py CHANGED
@@ -1,145 +1,122 @@
1
- import json
2
  import pandas as pd
3
- import numpy as np
4
  import matplotlib.pyplot as plt
 
5
  import os
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- file = input("Select the file to analyze or type in the file name (Should be .xlsx)")
9
- INPUT_EXCEL = file
10
-
11
- df = pd.read_excel(INPUT_EXCEL)
12
-
13
-
14
- ################DICTIONARY BASED ON THE PARAMETER###########################
15
- import json
16
-
17
- df_new = df.head(3)
18
- ##To drop the extra columns
19
- df_new = df_new.dropna(axis=1, how='all')
20
- df_param = df_new.drop(["T_TIME","SITE_NUM"],axis=1)
21
- parameter = list(df_param.columns)
22
-
23
- ##Convert the parameter to dictionary
24
- new_dict = {param:{"values":[]} for param in parameter}
25
- for prm in parameter:
26
- temp = dict(zip(df_new['SITE_NUM'],df_new[prm]))
27
- new_dict[prm].update(temp)
28
-
29
- for prm in parameter:
30
- df = df.dropna(axis=1, how='all')
31
- __temp = df[prm].values[4:].tolist()
32
- new_dict[prm]['values'].extend(__temp)
33
-
34
- ######To extract the Limits##############
35
- df_new = df.head(3)
36
- ##To drop the extra columns
37
- df_new = df_new.dropna(axis=1, how='all')
38
- df_param = df_new.drop(["T_TIME","SITE_NUM"],axis=1)
39
- parameter = list(df_param.columns)
40
-
41
- ##Convert the parameter to dictionary
42
- new_dict = {param:{"values":[]} for param in parameter}
43
- for prm in parameter:
44
- temp = dict(zip(df_new['SITE_NUM'],df_new[prm]))
45
- new_dict[prm].update(temp)
46
-
47
- for prm in parameter:
48
- df = df.dropna(axis=1, how='all')
49
- __temp = df[prm].values[4:].tolist()
50
- new_dict[prm]['values'].extend(__temp)
51
-
52
-
53
- #TODO: No need to store json. If in case if we want to maintian history then we can store them
54
- # json_data = json.dumps(new_dict)
55
- # print(json_data)
56
-
57
- # with open("output.json", "w") as f:
58
- # json.dump(new_dict, f, indent=4)
59
-
60
-
61
-
62
- #############Plotting###############
63
-
64
- data = new_dict
65
-
66
- ##TODO: To plot for all the paramter. But need to check the way to handle it in the front end.
67
- for param in parameter:
68
-
69
- values = data[param]["values"]
70
  limit_l = data[param]["LimitL"]
71
  limit_u = data[param]["LimitU"]
72
  unit = data[param]["Unit"]
73
 
74
- import numpy as np
75
-
76
- values = np.array(values)
77
- mean = np.mean(values)
78
- std = np.std(values, ddof=1) # Sample standard deviation
79
-
80
- UCL = mean + 3*std
81
- LCL = mean - 3*std
82
-
83
- plt.figure(figsize=(7, 5))
84
-
85
- # --- Box Plot ---
86
- plt.boxplot(values, vert=True, patch_artist=True)
87
-
88
- # --- Jittered Scatter Plot (spread raw values) ---
89
- y = values
90
- x = np.random.normal(1, 0.04, size=len(values)) # jitter around x=1
91
- plt.scatter(x, y, alpha=0.6)
92
-
93
- # --- Reference Lines ---
94
- plt.axhline(mean, color='green', linestyle='--', label='Mean')
95
- plt.axhline(UCL, color='red', linestyle='-.', label='UCL (Mean + )')
96
- plt.axhline(LCL, color='red', linestyle='--', label='LCL (Mean - 3σ)')
97
-
98
- # Optional spec limits
99
- plt.axhline(limit_l, color='orange', linestyle=':', label='Lower Spec Limit')
100
- plt.axhline(limit_u, color='orange', linestyle=':', label='Upper Spec Limit')
101
-
102
- # Labels & Styling
103
- plt.title(f"Box Plot with All Data Points - {param} ({unit})")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  plt.ylabel(f"Value ({unit})")
105
  plt.grid(True)
106
  plt.legend()
107
-
108
  plt.tight_layout()
109
- # plt.show()
110
- # chart_path = f"./charts/control_chart_{param}.png"
111
 
112
- # Folder path
113
- folder = "./charts"
114
-
115
- # Create folder if not exists
116
- os.makedirs(folder, exist_ok=True)
117
-
118
- # File path
119
- chart_path = f"{folder}/control_chart_{param}.png"
120
-
121
-
122
- plt.savefig(chart_path, dpi=300, bbox_inches='tight')
123
  plt.close()
124
-
125
-
126
- ####line plot
127
- # x_axis = range(1, len(values)+1)
128
- # plt.figure(figsize=(10,5))
129
- # plt.plot(x_axis,values, marker='o', linestyle='-', label='Measurements')
130
- # plt.axhline(mean, color='green', linestyle='--', label='Mean')
131
- # plt.axhline(UCL, color='red', linestyle='-.', label='UCL (Mean + 3σ)')
132
- # plt.axhline(LCL, color='red', linestyle='--', label='LCL (Mean - 3σ)')
133
- # plt.axhline(limit_l, color='orange', linestyle=':', label='Lower Spec Limit')
134
- # plt.axhline(limit_u, color='orange', linestyle=':', label='Upper Spec Limit')
135
-
136
- # plt.xticks(x_axis)
137
- # plt.title(f"SPC Chart - {param} ({unit})")
138
- # plt.xlabel("Sample Index")
139
- # plt.ylabel(f"Value ({unit})")
140
- # plt.legend()
141
- # plt.grid(True)
142
- # plt.tight_layout()
143
- # plt.show()
144
-
145
-
 
 
1
  import pandas as pd
 
2
  import matplotlib.pyplot as plt
3
+ import numpy as np
4
  import os
5
 
6
+ # --------- Load three datasets ----------
7
+ df_t1 = pd.read_excel("tester#1.xlsx")
8
+ df_t2 = pd.read_excel("tester#2.xlsx")
9
+ df_gold = pd.read_excel("Golden_Data.xlsx")
10
+
11
+ # --------- Get parameter list ----------
12
+ df_new = df_gold.head(3).dropna(axis=1, how="all")
13
+ df_param = df_new.drop(["T_TIME", "SITE_NUM"], axis=1)
14
+ parameters = list(df_param.columns)
15
+
16
+ # --------- Build master dictionary ----------
17
+ data = {
18
+ param: {
19
+ "Tester1": pd.to_numeric(df_t1[param].iloc[3:], errors="coerce").dropna().tolist(),
20
+ "Tester2": pd.to_numeric(df_t2[param].iloc[3:], errors="coerce").dropna().tolist(),
21
+ "Golden": pd.to_numeric(df_gold[param].iloc[3:], errors="coerce").dropna().tolist(),
22
+ "LimitL": df_new[param].iloc[1],
23
+ "LimitU": df_new[param].iloc[2],
24
+ "Unit": df_new[param].iloc[0]
25
+ }
26
+ for param in parameters
27
+ }
28
+
29
+ # --------- Plot comparison SPC ----------
30
+ os.makedirs("./charts_compare", exist_ok=True)
31
+
32
+ for param in parameters:
33
+
34
+ t1 = np.array(data[param]["Tester1"])
35
+ t2 = np.array(data[param]["Tester2"])
36
+ gold = np.array(data[param]["Golden"])
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  limit_l = data[param]["LimitL"]
39
  limit_u = data[param]["LimitU"]
40
  unit = data[param]["Unit"]
41
 
42
+ # Golden reference control band
43
+ mean = gold.mean()
44
+ t1_mean = t1.mean()
45
+ t2_mean = t2.mean()
46
+ std = gold.std(ddof=1)
47
+ UCL = mean + 3 * std
48
+ LCL = mean - 3 * std
49
+
50
+ # ---- Fix max length ----
51
+ max_len = max(len(t1), len(t2), len(gold))
52
+ xaxis = np.arange(1, max_len + 1)
53
+
54
+ # ---- Correlation ----
55
+ min_len_t1 = min(len(t1), len(gold))
56
+ min_len_t2 = min(len(t2), len(gold))
57
+
58
+ corr_t1 = np.corrcoef(t1[:min_len_t1], gold[:min_len_t1])[0,1]
59
+ corr_t2 = np.corrcoef(t2[:min_len_t2], gold[:min_len_t2])[0,1]
60
+ corr_t1_t2 = np.corrcoef(t1[:min_len_t1], t2[:min_len_t2])[0,1]
61
+
62
+ # ---- CPK (based on Golden dataset) ----
63
+ cpk = min((mean - limit_l) / (3 * std), (limit_u - mean) / (3 * std))
64
+
65
+ plt.figure(figsize=(10,6))
66
+
67
+ # --- Plot all datasets ---
68
+ plt.plot(range(1, len(t1)+1), t1, marker='o', label="Tester #1")
69
+ plt.plot(range(1, len(t2)+1), t2, marker='o', label="Tester #2")
70
+ plt.plot(range(1, len(gold)+1), gold, marker='o', label="Gold Reference", linewidth=3)
71
+
72
+ # --- SPC lines ---
73
+ plt.axhline(mean, linestyle='--', color='black', label=f"Mean (Gold)")
74
+ plt.axhline(UCL, linestyle='-.', color='red', label="UCL (Mean + 3σ)")
75
+ plt.axhline(LCL, linestyle='-.', color='red', label="LCL (Mean – 3σ)")
76
+
77
+ # --- Spec Limits ---
78
+ plt.axhline(limit_l, linestyle=':', color='orange', label="Lower Spec")
79
+ plt.axhline(limit_u, linestyle=':', color='orange', label="Upper Spec")
80
+
81
+ # ---- Fix X-axis ----
82
+ # plt.xticks(np.arange(1, max_len + 1, step=1))
83
+ # plt.xlim(1, max_len)
84
+
85
+ # ---- Fix X-axis with whole numbers + padding ----
86
+ max_len = max(len(t1), len(t2), len(gold))
87
+
88
+ plt.xticks(np.arange(1, max_len + 1, 1)) # whole numbers
89
+ plt.xlim(0, max_len + 1) # space before 1 and after last point
90
+
91
+
92
+ # ---- Add CPK + Correlation text box ----
93
+ textstr = (
94
+ f"Gold Mean = {mean:.4f}\n"
95
+ f"Std Dev = {std:.4f}\n"
96
+ f"CPK = {cpk:.4f}\n"
97
+ f"Corr T1–Gold = {corr_t1:.4f}\n"
98
+ f"Corr T2–Gold = {corr_t2:.4f}\n"
99
+ f"Corr T1-T2 = {corr_t1_t2:.4f}\n"
100
+ f"Tester#1 Mean = {t1_mean:.4f}\n"
101
+ f"Tester#2 Mean = {t2_mean:4f}\n"
102
+ )
103
+
104
+ plt.gca().text(
105
+ 0.02, 0.98, textstr,
106
+ transform=plt.gca().transAxes,
107
+ fontsize=10,
108
+ verticalalignment='top',
109
+ bbox=dict(boxstyle="round,pad=0.4", facecolor="white", alpha=0.8)
110
+ )
111
+
112
+ # Labels
113
+ plt.title(f"SPC Comparison - {param} ({unit})")
114
+ plt.xlabel("Sample Index")
115
  plt.ylabel(f"Value ({unit})")
116
  plt.grid(True)
117
  plt.legend()
 
118
  plt.tight_layout()
 
 
119
 
120
+ # Save chart
121
+ plt.savefig(f"./charts_compare/SPC_compare_{param}.png", dpi=300)
 
 
 
 
 
 
 
 
 
122
  plt.close()