Initial commit: CMM Report Analyzer
FastAPI app that parses CMM inspection reports (PDF/Excel/CSV), computes SPC metrics (Cp/Cpk/Pp/Ppk, control limits, Shapiro-Wilk), generates interactive Plotly charts, and provides AI-powered quality summaries via Azure OpenAI with graceful fallback. Includes 21 passing tests covering parsers, SPC calculations, and API endpoints.
This commit is contained in:
86
app/analysis/charts.py
Normal file
86
app/analysis/charts.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import plotly.graph_objects as go
|
||||
|
||||
from app.analysis.spc import SPCResult
|
||||
|
||||
|
||||
def histogram(result: SPCResult) -> dict:
|
||||
"""Distribution histogram with spec limits overlay."""
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Histogram(x=result.values, name="Measurements", nbinsx=20))
|
||||
fig.add_vline(x=result.usl, line_dash="dash", line_color="red",
|
||||
annotation_text="USL")
|
||||
fig.add_vline(x=result.lsl, line_dash="dash", line_color="red",
|
||||
annotation_text="LSL")
|
||||
fig.add_vline(x=result.nominal, line_dash="dot", line_color="green",
|
||||
annotation_text="Nominal")
|
||||
fig.update_layout(
|
||||
title=f"Distribution – {result.feature_name}",
|
||||
xaxis_title="Value", yaxis_title="Count",
|
||||
template="plotly_white", height=350,
|
||||
)
|
||||
return fig.to_plotly_json()
|
||||
|
||||
|
||||
def control_chart(result: SPCResult) -> dict:
|
||||
"""Individual values control chart (I-chart)."""
|
||||
x_axis = list(range(1, result.n + 1))
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Scatter(
|
||||
x=x_axis, y=result.values, mode="lines+markers", name="Value",
|
||||
))
|
||||
fig.add_hline(y=result.mean, line_color="green", annotation_text="Mean")
|
||||
fig.add_hline(y=result.ucl, line_dash="dash", line_color="red",
|
||||
annotation_text="UCL")
|
||||
fig.add_hline(y=result.lcl, line_dash="dash", line_color="red",
|
||||
annotation_text="LCL")
|
||||
fig.add_hline(y=result.usl, line_dash="dot", line_color="orange",
|
||||
annotation_text="USL")
|
||||
fig.add_hline(y=result.lsl, line_dash="dot", line_color="orange",
|
||||
annotation_text="LSL")
|
||||
fig.update_layout(
|
||||
title=f"Control Chart – {result.feature_name}",
|
||||
xaxis_title="Sample #", yaxis_title="Value",
|
||||
template="plotly_white", height=350,
|
||||
)
|
||||
return fig.to_plotly_json()
|
||||
|
||||
|
||||
def capability_bar(results: list[SPCResult]) -> dict:
|
||||
"""Capability index bar chart comparing all features."""
|
||||
names = [r.feature_name for r in results]
|
||||
cpk_vals = [r.cpk if r.cpk is not None else 0.0 for r in results]
|
||||
ppk_vals = [r.ppk if r.ppk is not None else 0.0 for r in results]
|
||||
|
||||
colors = ["#2ecc71" if v >= 1.33 else "#f39c12" if v >= 1.0 else "#e74c3c"
|
||||
for v in cpk_vals]
|
||||
|
||||
fig = go.Figure()
|
||||
fig.add_trace(go.Bar(x=names, y=cpk_vals, name="Cpk", marker_color=colors))
|
||||
fig.add_trace(go.Bar(x=names, y=ppk_vals, name="Ppk", marker_color="rgba(52,152,219,0.6)"))
|
||||
fig.add_hline(y=1.33, line_dash="dash", line_color="green",
|
||||
annotation_text="Cpk=1.33")
|
||||
fig.add_hline(y=1.0, line_dash="dot", line_color="orange",
|
||||
annotation_text="Cpk=1.0")
|
||||
fig.update_layout(
|
||||
title="Process Capability Summary",
|
||||
xaxis_title="Feature", yaxis_title="Index",
|
||||
barmode="group", template="plotly_white", height=400,
|
||||
)
|
||||
return fig.to_plotly_json()
|
||||
|
||||
|
||||
def generate_charts(results: list[SPCResult]) -> dict:
|
||||
"""Generate all charts for a set of SPC results."""
|
||||
charts: dict[str, list[dict] | dict] = {
|
||||
"histograms": [],
|
||||
"control_charts": [],
|
||||
}
|
||||
for r in results:
|
||||
if r.n >= 2:
|
||||
charts["histograms"].append(histogram(r))
|
||||
charts["control_charts"].append(control_chart(r))
|
||||
if results:
|
||||
charts["capability_bar"] = capability_bar(results)
|
||||
return charts
|
||||
Reference in New Issue
Block a user