quality_results_panel.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. """
  2. Quality Results Panel
  3. Panel for displaying comprehensive quality grading results with breakdown.
  4. """
  5. from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
  6. QSizePolicy, QProgressBar, QFrame)
  7. from PyQt5.QtCore import Qt
  8. from PyQt5.QtGui import QFont, QColor
  9. from ui.widgets.panel_header import PanelHeader
  10. class QualityResultsPanel(QWidget):
  11. """
  12. Panel for displaying quality grading results.
  13. Shows final grade, grading breakdown with progress bars, and additional metrics.
  14. """
  15. def __init__(self, parent=None):
  16. super().__init__(parent)
  17. self.current_grade = "B"
  18. self.overall_score = 78.5
  19. self.grade_colors = {
  20. 'A': '#27ae60',
  21. 'B': '#f39c12',
  22. 'C': '#e74c3c'
  23. }
  24. self.init_ui()
  25. def init_ui(self):
  26. """Initialize the panel UI."""
  27. # Set size policy
  28. self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
  29. layout = QVBoxLayout(self)
  30. layout.setContentsMargins(0, 0, 0, 0)
  31. layout.setSpacing(0)
  32. # Main panel container with card styling
  33. self.setStyleSheet("""
  34. QWidget {
  35. background-color: white;
  36. border: 1px solid #ddd;
  37. }
  38. """)
  39. # Header using the PanelHeader widget
  40. header = PanelHeader(
  41. title="Quality Grading Results",
  42. color="#27ae60" # Green for results/grading
  43. )
  44. layout.addWidget(header)
  45. # Content area
  46. content = QWidget()
  47. content.setStyleSheet("""
  48. background-color: #2c3e50;
  49. border: 1px solid #34495e;
  50. border-top: none;
  51. """)
  52. content_layout = QVBoxLayout(content)
  53. content_layout.setContentsMargins(10, 10, 10, 10)
  54. content_layout.setSpacing(12)
  55. # Final Grade Display
  56. self._create_grade_display(content_layout)
  57. # Separator
  58. self._add_separator(content_layout)
  59. # Grading Breakdown Section
  60. self._create_grading_breakdown(content_layout)
  61. # Separator
  62. self._add_separator(content_layout)
  63. # Overall Score Display
  64. self._create_overall_score(content_layout)
  65. # Separator
  66. self._add_separator(content_layout)
  67. # Additional Metrics Section
  68. self._create_additional_metrics(content_layout)
  69. layout.addWidget(content, 1)
  70. def _create_grade_display(self, parent_layout):
  71. """Create the final grade display widget."""
  72. # Grade widget container
  73. grade_widget = QWidget()
  74. grade_widget.setFixedHeight(70)
  75. grade_widget.setStyleSheet(f"""
  76. QWidget {{
  77. background-color: {self.grade_colors.get(self.current_grade, '#95a5a6')};
  78. border-radius: 8px;
  79. border: 2px solid;
  80. }}
  81. """)
  82. grade_layout = QVBoxLayout(grade_widget)
  83. grade_layout.setContentsMargins(15, 10, 15, 10)
  84. grade_layout.setAlignment(Qt.AlignCenter)
  85. # Grade title
  86. grade_title = QLabel("FINAL QUALITY GRADE")
  87. grade_title.setFont(QFont("Arial", 10, QFont.Bold))
  88. grade_title.setStyleSheet("color: white;")
  89. grade_title.setAlignment(Qt.AlignCenter)
  90. # Grade value (large)
  91. self.grade_value_label = QLabel(self.current_grade)
  92. self.grade_value_label.setFont(QFont("Arial", 32, QFont.Bold))
  93. self.grade_value_label.setStyleSheet("color: white;")
  94. self.grade_value_label.setAlignment(Qt.AlignCenter)
  95. grade_layout.addWidget(grade_title)
  96. grade_layout.addWidget(self.grade_value_label)
  97. parent_layout.addWidget(grade_widget)
  98. def _create_grading_breakdown(self, parent_layout):
  99. """Create the grading breakdown section with progress bars."""
  100. # Section label
  101. breakdown_label = QLabel("Grading Breakdown:")
  102. breakdown_label.setFont(QFont("Arial", 11, QFont.Bold))
  103. breakdown_label.setStyleSheet("color: #ecf0f1;")
  104. parent_layout.addWidget(breakdown_label)
  105. # Sample grading metrics (including locule count)
  106. sample_metrics = [
  107. {"name": "Size & Weight", "value": 90, "color": "#27ae60"},
  108. {"name": "Shape Regularity", "value": 92, "color": "#27ae60"},
  109. {"name": "Locule Count", "value": 95, "color": "#3498db"}, # High score for correct locule count
  110. {"name": "Surface Quality", "value": 70, "color": "#f39c12"},
  111. {"name": "Color Uniformity", "value": 82, "color": "#27ae60"},
  112. {"name": "Firmness (Thermal)", "value": 0, "color": "#7f8c8d"}
  113. ]
  114. self.metric_bars = {}
  115. for metric in sample_metrics:
  116. metric_widget = self._create_metric_bar(
  117. metric["name"], metric["value"], metric["color"]
  118. )
  119. parent_layout.addWidget(metric_widget)
  120. def _create_metric_bar(self, name, value, color):
  121. """Create a single metric progress bar."""
  122. # Container widget
  123. widget = QWidget()
  124. widget.setFixedHeight(25)
  125. layout = QHBoxLayout(widget)
  126. layout.setContentsMargins(0, 0, 0, 0)
  127. layout.setSpacing(8)
  128. # Metric name label
  129. name_label = QLabel(name)
  130. name_label.setFont(QFont("Arial", 9))
  131. name_label.setStyleSheet("color: #ecf0f1;")
  132. name_label.setFixedWidth(130)
  133. # Progress bar
  134. progress_bar = QProgressBar()
  135. progress_bar.setValue(value)
  136. progress_bar.setTextVisible(False)
  137. progress_bar.setFixedHeight(18)
  138. progress_bar.setStyleSheet(f"""
  139. QProgressBar {{
  140. border: 1px solid #4a5f7a;
  141. border-radius: 3px;
  142. background-color: #34495e;
  143. text-align: center;
  144. }}
  145. QProgressBar::chunk {{
  146. background-color: {color};
  147. border-radius: 2px;
  148. }}
  149. """)
  150. # Value label (shows percentage or N/A)
  151. if value > 0:
  152. value_text = f"{value}%"
  153. value_color = color
  154. else:
  155. value_text = "N/A"
  156. value_color = "#7f8c8d"
  157. value_label = QLabel(value_text)
  158. value_label.setFont(QFont("Arial", 9, QFont.Bold))
  159. value_label.setStyleSheet(f"color: {value_color};")
  160. value_label.setFixedWidth(35)
  161. value_label.setAlignment(Qt.AlignCenter)
  162. # Store reference for updates
  163. widget.progress_bar = progress_bar
  164. widget.value_label = value_label
  165. self.metric_bars[name] = widget
  166. layout.addWidget(name_label)
  167. layout.addWidget(progress_bar, 1)
  168. layout.addWidget(value_label)
  169. return widget
  170. def _create_overall_score(self, parent_layout):
  171. """Create the overall score display."""
  172. # Overall score widget
  173. overall_widget = QWidget()
  174. overall_widget.setStyleSheet("""
  175. QWidget {
  176. background-color: #34495e;
  177. border-radius: 5px;
  178. border: 1px solid #4a5f7a;
  179. }
  180. """)
  181. overall_layout = QHBoxLayout(overall_widget)
  182. overall_layout.setContentsMargins(15, 10, 15, 10)
  183. overall_layout.setSpacing(10)
  184. # Label
  185. overall_label = QLabel("Overall Quality Score:")
  186. overall_label.setFont(QFont("Arial", 11, QFont.Bold))
  187. overall_label.setStyleSheet("color: #ecf0f1;")
  188. # Score value (large and prominent)
  189. self.overall_score_label = QLabel(f"{self.overall_score:.1f}%")
  190. self.overall_score_label.setFont(QFont("Arial", 18, QFont.Bold))
  191. # Color code based on score ranges
  192. if self.overall_score >= 90:
  193. score_color = "#27ae60" # Green for excellent
  194. elif self.overall_score >= 75:
  195. score_color = "#f39c12" # Orange for good
  196. else:
  197. score_color = "#e74c3c" # Red for poor
  198. self.overall_score_label.setStyleSheet(f"color: {score_color};")
  199. overall_layout.addWidget(overall_label)
  200. overall_layout.addStretch()
  201. overall_layout.addWidget(self.overall_score_label)
  202. parent_layout.addWidget(overall_widget)
  203. def _create_additional_metrics(self, parent_layout):
  204. """Create additional metrics section."""
  205. # Section label
  206. metrics_label = QLabel("Additional Metrics:")
  207. metrics_label.setFont(QFont("Arial", 10, QFont.Bold))
  208. metrics_label.setStyleSheet("color: #ecf0f1;")
  209. parent_layout.addWidget(metrics_label)
  210. # Metrics container
  211. metrics_widget = QWidget()
  212. metrics_widget.setStyleSheet("""
  213. QWidget {
  214. background-color: #34495e;
  215. border-radius: 3px;
  216. border: 1px solid #4a5f7a;
  217. }
  218. """)
  219. metrics_layout = QVBoxLayout(metrics_widget)
  220. metrics_layout.setContentsMargins(10, 8, 10, 8)
  221. metrics_layout.setSpacing(3)
  222. # Sample additional metrics
  223. sample_metrics = [
  224. "• Estimated Weight: 185g",
  225. "• Diameter: 72mm (equatorial)",
  226. "• Aspect Ratio: 0.85 (oblate)",
  227. "• Surface Defect Coverage: 3.2%",
  228. "• Processing Time: 2.7s"
  229. ]
  230. for metric in sample_metrics:
  231. metric_label = QLabel(metric)
  232. metric_label.setFont(QFont("Arial", 8))
  233. metric_label.setStyleSheet("color: #bdc3c7;")
  234. metrics_layout.addWidget(metric_label)
  235. # Model version info
  236. model_label = QLabel("Model: QualityNet v2.8")
  237. model_label.setFont(QFont("Arial", 8))
  238. model_label.setStyleSheet("color: #7f8c8d;")
  239. metrics_layout.addWidget(model_label)
  240. parent_layout.addWidget(metrics_widget)
  241. def _add_separator(self, parent_layout):
  242. """Add a visual separator line."""
  243. separator = QFrame()
  244. separator.setFrameShape(QFrame.HLine)
  245. separator.setStyleSheet("color: #4a5f7a;")
  246. separator.setFixedHeight(1)
  247. parent_layout.addWidget(separator)
  248. def update_grade(self, grade, score):
  249. """Update the grade and score display."""
  250. self.current_grade = grade
  251. self.overall_score = score
  252. # Update grade display
  253. self.grade_value_label.setText(grade)
  254. # Update grade background color
  255. grade_color = self.grade_colors.get(grade, '#95a5a6')
  256. # Find the grade widget and update its color
  257. for i in range(self.layout().count()):
  258. child = self.layout().itemAt(i).widget()
  259. if hasattr(child, 'setStyleSheet'): # Grade display widget
  260. child.setStyleSheet(f"""
  261. QWidget {{
  262. background-color: {grade_color};
  263. border-radius: 8px;
  264. border: 2px solid;
  265. }}
  266. """)
  267. # Update overall score
  268. self.overall_score_label.setText(f"{score:.1f}%")
  269. # Update score color
  270. if score >= 90:
  271. score_color = "#27ae60"
  272. elif score >= 75:
  273. score_color = "#f39c12"
  274. else:
  275. score_color = "#e74c3c"
  276. self.overall_score_label.setStyleSheet(f"color: {score_color}; font-size: 18px; font-weight: bold;")
  277. def update_locule_count(self, count: int, confidence: float = 94.5):
  278. """Update the locule count metric in the grading breakdown."""
  279. # Update the metric bar for locule count
  280. if "Locule Count" in self.metric_bars:
  281. widget = self.metric_bars["Locule Count"]
  282. # Calculate score based on locule count (4 is ideal for durian)
  283. # Perfect score (95%) for count=4, lower scores for other counts
  284. if count == 4:
  285. score = 95
  286. elif count == 3 or count == 5:
  287. score = 85
  288. elif count == 2 or count == 6:
  289. score = 70
  290. else:
  291. score = 50
  292. # Update progress bar
  293. widget.progress_bar.setValue(score)
  294. # Update value label (show both count and score)
  295. value_text = f"4/{count}" # Shows expected vs actual
  296. if count == 4:
  297. value_color = "#27ae60" # Green for correct count
  298. elif count >= 3 and count <= 5:
  299. value_color = "#f39c12" # Orange for acceptable range
  300. else:
  301. value_color = "#e74c3c" # Red for poor count
  302. widget.value_label.setText(value_text)
  303. widget.value_label.setStyleSheet(f"color: {value_color}; font-weight: bold;")
  304. def update_metric(self, metric_name, value):
  305. """Update a specific metric value."""
  306. if metric_name in self.metric_bars:
  307. widget = self.metric_bars[metric_name]
  308. # Update progress bar
  309. widget.progress_bar.setValue(value)
  310. # Update value label
  311. if value > 0:
  312. value_text = f"{value}%"
  313. # Update color based on value
  314. if value >= 90:
  315. color = "#27ae60"
  316. elif value >= 75:
  317. color = "#f39c12"
  318. else:
  319. color = "#e74c3c"
  320. else:
  321. value_text = "N/A"
  322. color = "#7f8c8d"
  323. widget.value_label.setText(value_text)
  324. widget.value_label.setStyleSheet(f"color: {color}; font-weight: bold;")