Spaces:
Sleeping
Sleeping
Commit
Β·
2546160
1
Parent(s):
58bde6b
Golden data fixed
Browse files- app.py +68 -41
- templates/index.html +19 -8
- templates/plot.html +6 -10
app.py
CHANGED
|
@@ -1,27 +1,28 @@
|
|
| 1 |
-
from flask import Flask, render_template, request, send_file
|
| 2 |
import pandas as pd
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
import numpy as np
|
| 5 |
import io
|
| 6 |
-
import os
|
| 7 |
|
| 8 |
app = Flask(__name__)
|
| 9 |
|
| 10 |
-
#
|
| 11 |
-
data_cache = {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
|
| 14 |
-
def
|
| 15 |
-
"""Load
|
| 16 |
limits_df1 = pd.read_excel(golden_file, nrows=4)
|
| 17 |
df1 = pd.read_excel(golden_file)
|
| 18 |
df1 = df1.drop([0, 1, 2, 3])
|
| 19 |
-
df2 = pd.read_excel(test_file)
|
| 20 |
-
df2 = df2.drop([0, 1, 2, 3])
|
| 21 |
-
|
| 22 |
df1 = df1.apply(pd.to_numeric, errors="coerce")
|
| 23 |
-
df2 = df2.apply(pd.to_numeric, errors="coerce")
|
| 24 |
|
|
|
|
| 25 |
limits_df1 = limits_df1.drop([0])
|
| 26 |
ignore_cols = ["SITE_NUM", "PART_ID", "PASSFG", "SOFT_BIN", "T_TIME", "TEST_NUM"]
|
| 27 |
cols_to_plot = [col for col in limits_df1.columns if "_" in col and col not in ignore_cols]
|
|
@@ -32,28 +33,39 @@ def process_files(golden_file, test_file):
|
|
| 32 |
for col in limits_df1.columns
|
| 33 |
}
|
| 34 |
|
| 35 |
-
# Store
|
| 36 |
-
data_cache["df1"]
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
|
| 39 |
-
def
|
| 40 |
-
"""
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
-
|
| 44 |
-
|
|
|
|
| 45 |
|
| 46 |
plt.figure(figsize=(6, 4))
|
| 47 |
|
|
|
|
| 48 |
x1 = np.arange(1, len(df1[col]) + 1)
|
| 49 |
y1 = pd.to_numeric(df1[col], errors="coerce").values
|
| 50 |
plt.plot(x1, y1, marker="o", linestyle="-", color="blue", label="Golden")
|
| 51 |
|
|
|
|
| 52 |
if col in df2.columns:
|
| 53 |
x2 = np.arange(1, len(df2[col]) + 1)
|
| 54 |
y2 = pd.to_numeric(df2[col], errors="coerce").values
|
| 55 |
plt.plot(x2, y2, marker="s", linestyle="--", color="red", label="Test")
|
| 56 |
|
|
|
|
| 57 |
if col in limits:
|
| 58 |
ll, ul = limits[col]["LL"], limits[col]["UL"]
|
| 59 |
plt.axhline(ll, color="green", linestyle="--", linewidth=2, label="LL")
|
|
@@ -75,40 +87,55 @@ def generate_plot(col):
|
|
| 75 |
|
| 76 |
@app.route("/", methods=["GET", "POST"])
|
| 77 |
def index():
|
|
|
|
| 78 |
if request.method == "POST":
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
|
| 103 |
@app.route("/plot_image/<col>")
|
| 104 |
def plot_image(col):
|
| 105 |
-
"""
|
|
|
|
|
|
|
|
|
|
| 106 |
try:
|
| 107 |
-
buf = generate_plot(col)
|
| 108 |
return send_file(buf, mimetype="image/png")
|
| 109 |
except Exception as e:
|
| 110 |
return f"Error generating plot: {str(e)}"
|
| 111 |
|
| 112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
if __name__ == "__main__":
|
| 114 |
app.run(host="0.0.0.0", port=7860, debug=True)
|
|
|
|
| 1 |
+
from flask import Flask, render_template, request, send_file, redirect, url_for
|
| 2 |
import pandas as pd
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
import numpy as np
|
| 5 |
import io
|
|
|
|
| 6 |
|
| 7 |
app = Flask(__name__)
|
| 8 |
|
| 9 |
+
# Global data cache
|
| 10 |
+
data_cache = {
|
| 11 |
+
"df1": None, # Golden data
|
| 12 |
+
"limits": {},
|
| 13 |
+
"cols": [],
|
| 14 |
+
"golden_loaded": False
|
| 15 |
+
}
|
| 16 |
|
| 17 |
|
| 18 |
+
def process_golden_file(golden_file):
|
| 19 |
+
"""Load and store Golden Excel data + limits."""
|
| 20 |
limits_df1 = pd.read_excel(golden_file, nrows=4)
|
| 21 |
df1 = pd.read_excel(golden_file)
|
| 22 |
df1 = df1.drop([0, 1, 2, 3])
|
|
|
|
|
|
|
|
|
|
| 23 |
df1 = df1.apply(pd.to_numeric, errors="coerce")
|
|
|
|
| 24 |
|
| 25 |
+
# Extract limits
|
| 26 |
limits_df1 = limits_df1.drop([0])
|
| 27 |
ignore_cols = ["SITE_NUM", "PART_ID", "PASSFG", "SOFT_BIN", "T_TIME", "TEST_NUM"]
|
| 28 |
cols_to_plot = [col for col in limits_df1.columns if "_" in col and col not in ignore_cols]
|
|
|
|
| 33 |
for col in limits_df1.columns
|
| 34 |
}
|
| 35 |
|
| 36 |
+
# Store globally
|
| 37 |
+
data_cache["df1"] = df1
|
| 38 |
+
data_cache["limits"] = limits
|
| 39 |
+
data_cache["cols"] = cols_to_plot
|
| 40 |
+
data_cache["golden_loaded"] = True
|
| 41 |
|
| 42 |
|
| 43 |
+
def process_test_file(test_file):
|
| 44 |
+
"""Load and return the Test Excel data."""
|
| 45 |
+
df2 = pd.read_excel(test_file)
|
| 46 |
+
df2 = df2.drop([0, 1, 2, 3])
|
| 47 |
+
df2 = df2.apply(pd.to_numeric, errors="coerce")
|
| 48 |
+
return df2
|
| 49 |
+
|
| 50 |
|
| 51 |
+
def generate_plot(df2, col):
|
| 52 |
+
"""Generate plot comparing Golden and Test for a specific column."""
|
| 53 |
+
df1, limits = data_cache["df1"], data_cache["limits"]
|
| 54 |
|
| 55 |
plt.figure(figsize=(6, 4))
|
| 56 |
|
| 57 |
+
# Golden
|
| 58 |
x1 = np.arange(1, len(df1[col]) + 1)
|
| 59 |
y1 = pd.to_numeric(df1[col], errors="coerce").values
|
| 60 |
plt.plot(x1, y1, marker="o", linestyle="-", color="blue", label="Golden")
|
| 61 |
|
| 62 |
+
# Test
|
| 63 |
if col in df2.columns:
|
| 64 |
x2 = np.arange(1, len(df2[col]) + 1)
|
| 65 |
y2 = pd.to_numeric(df2[col], errors="coerce").values
|
| 66 |
plt.plot(x2, y2, marker="s", linestyle="--", color="red", label="Test")
|
| 67 |
|
| 68 |
+
# Limits
|
| 69 |
if col in limits:
|
| 70 |
ll, ul = limits[col]["LL"], limits[col]["UL"]
|
| 71 |
plt.axhline(ll, color="green", linestyle="--", linewidth=2, label="LL")
|
|
|
|
| 87 |
|
| 88 |
@app.route("/", methods=["GET", "POST"])
|
| 89 |
def index():
|
| 90 |
+
"""Handle golden upload (if not loaded) or test upload (if golden loaded)."""
|
| 91 |
if request.method == "POST":
|
| 92 |
+
if not data_cache["golden_loaded"]:
|
| 93 |
+
# Upload Golden
|
| 94 |
+
golden_file = request.files.get("golden_file")
|
| 95 |
+
if not golden_file:
|
| 96 |
+
return render_template("index.html", error="Please upload a Golden file first.")
|
| 97 |
+
try:
|
| 98 |
+
process_golden_file(golden_file)
|
| 99 |
+
return render_template("index.html", message="Golden data loaded successfully! Now upload Test data.")
|
| 100 |
+
except Exception as e:
|
| 101 |
+
return render_template("index.html", error=f"Error loading Golden file: {e}")
|
| 102 |
+
else:
|
| 103 |
+
# Upload Test
|
| 104 |
+
test_file = request.files.get("test_file")
|
| 105 |
+
if not test_file:
|
| 106 |
+
return render_template("index.html", error="Please upload a Test file.")
|
| 107 |
+
try:
|
| 108 |
+
df2 = process_test_file(test_file)
|
| 109 |
+
cols = data_cache["cols"]
|
| 110 |
+
preview_cols = cols[:3] if len(cols) >= 3 else cols
|
| 111 |
+
# Store test temporarily in memory (for this view only)
|
| 112 |
+
data_cache["df2_temp"] = df2
|
| 113 |
+
return render_template("plot.html", cols=cols, preview_cols=preview_cols)
|
| 114 |
+
except Exception as e:
|
| 115 |
+
return render_template("index.html", error=f"Error loading Test file: {e}")
|
| 116 |
+
|
| 117 |
+
return render_template("index.html", golden_loaded=data_cache["golden_loaded"])
|
| 118 |
|
| 119 |
|
| 120 |
@app.route("/plot_image/<col>")
|
| 121 |
def plot_image(col):
|
| 122 |
+
"""Generate plot image for selected column."""
|
| 123 |
+
df2 = data_cache.get("df2_temp")
|
| 124 |
+
if df2 is None:
|
| 125 |
+
return "No Test data uploaded yet."
|
| 126 |
try:
|
| 127 |
+
buf = generate_plot(df2, col)
|
| 128 |
return send_file(buf, mimetype="image/png")
|
| 129 |
except Exception as e:
|
| 130 |
return f"Error generating plot: {str(e)}"
|
| 131 |
|
| 132 |
|
| 133 |
+
@app.route("/reset_golden")
|
| 134 |
+
def reset_golden():
|
| 135 |
+
"""Clear the Golden file from memory."""
|
| 136 |
+
data_cache.update({"df1": None, "limits": {}, "cols": [], "golden_loaded": False})
|
| 137 |
+
return redirect(url_for("index"))
|
| 138 |
+
|
| 139 |
+
|
| 140 |
if __name__ == "__main__":
|
| 141 |
app.run(host="0.0.0.0", port=7860, debug=True)
|
templates/index.html
CHANGED
|
@@ -26,24 +26,35 @@
|
|
| 26 |
border-radius: 5px;
|
| 27 |
}
|
| 28 |
.error { color: red; }
|
|
|
|
| 29 |
</style>
|
| 30 |
</head>
|
| 31 |
<body>
|
| 32 |
<h2>π IPM Golden vs Test Data Visualizer</h2>
|
| 33 |
-
<p>Upload both Golden and Test Excel files to generate visual comparison.</p>
|
| 34 |
|
| 35 |
{% if error %}
|
| 36 |
<p class="error">{{ error }}</p>
|
| 37 |
{% endif %}
|
|
|
|
|
|
|
|
|
|
| 38 |
|
|
|
|
| 39 |
<form method="POST" enctype="multipart/form-data">
|
| 40 |
-
<
|
| 41 |
-
<input type="file" name="golden_file" accept=".xlsx" required><br
|
| 42 |
-
|
| 43 |
-
<label>Test Data (.xlsx):</label><br>
|
| 44 |
-
<input type="file" name="test_file" accept=".xlsx" required><br><br>
|
| 45 |
-
|
| 46 |
-
<button type="submit">Generate Plots</button>
|
| 47 |
</form>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
</body>
|
| 49 |
</html>
|
|
|
|
| 26 |
border-radius: 5px;
|
| 27 |
}
|
| 28 |
.error { color: red; }
|
| 29 |
+
.message { color: green; }
|
| 30 |
</style>
|
| 31 |
</head>
|
| 32 |
<body>
|
| 33 |
<h2>π IPM Golden vs Test Data Visualizer</h2>
|
|
|
|
| 34 |
|
| 35 |
{% if error %}
|
| 36 |
<p class="error">{{ error }}</p>
|
| 37 |
{% endif %}
|
| 38 |
+
{% if message %}
|
| 39 |
+
<p class="message">{{ message }}</p>
|
| 40 |
+
{% endif %}
|
| 41 |
|
| 42 |
+
{% if not golden_loaded %}
|
| 43 |
<form method="POST" enctype="multipart/form-data">
|
| 44 |
+
<h3>Step 1: Upload Golden Data (.xlsx)</h3>
|
| 45 |
+
<input type="file" name="golden_file" accept=".xlsx" required><br>
|
| 46 |
+
<button type="submit">Upload Golden</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
</form>
|
| 48 |
+
{% else %}
|
| 49 |
+
<form method="POST" enctype="multipart/form-data">
|
| 50 |
+
<h3>Step 2: Upload New Test Data (.xlsx)</h3>
|
| 51 |
+
<input type="file" name="test_file" accept=".xlsx" required><br>
|
| 52 |
+
<button type="submit">Upload Test Data</button>
|
| 53 |
+
</form>
|
| 54 |
+
<br>
|
| 55 |
+
<form action="/reset_golden">
|
| 56 |
+
<button style="background-color:#d9534f;">Reset Golden Data</button>
|
| 57 |
+
</form>
|
| 58 |
+
{% endif %}
|
| 59 |
</body>
|
| 60 |
</html>
|
templates/plot.html
CHANGED
|
@@ -33,17 +33,13 @@
|
|
| 33 |
</script>
|
| 34 |
</head>
|
| 35 |
<body>
|
| 36 |
-
<h2>π
|
| 37 |
|
| 38 |
<h3>Preview (First few plots):</h3>
|
| 39 |
-
{%
|
| 40 |
-
{
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
{% endfor %}
|
| 44 |
-
{% else %}
|
| 45 |
-
<p>No columns found for preview.</p>
|
| 46 |
-
{% endif %}
|
| 47 |
|
| 48 |
<hr>
|
| 49 |
<h3>View Other Columns</h3>
|
|
@@ -57,4 +53,4 @@
|
|
| 57 |
<br>
|
| 58 |
<img id="dynamic-plot" style="display:block; margin:auto; max-width:90%;">
|
| 59 |
</body>
|
| 60 |
-
</html>
|
|
|
|
| 33 |
</script>
|
| 34 |
</head>
|
| 35 |
<body>
|
| 36 |
+
<h2>π Golden vs Test Comparison</h2>
|
| 37 |
|
| 38 |
<h3>Preview (First few plots):</h3>
|
| 39 |
+
{% for c in preview_cols %}
|
| 40 |
+
<div class="preview-title">{{ c }}</div>
|
| 41 |
+
<img src="/plot_image/{{ c }}" alt="{{ c }}">
|
| 42 |
+
{% endfor %}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
<hr>
|
| 45 |
<h3>View Other Columns</h3>
|
|
|
|
| 53 |
<br>
|
| 54 |
<img id="dynamic-plot" style="display:block; margin:auto; max-width:90%;">
|
| 55 |
</body>
|
| 56 |
+
</html>
|