Теперь подсветка факторов эксперимента подсвечиваются соответственно значениям: + зелёным - красным, 0 (факторы с шагом в 0) - светлосерым. Убран лишний столбец в матрице факторного эксперимента

This commit is contained in:
2026-05-29 08:55:43 +05:00
parent 6400f04f1c
commit 2392735641
3 changed files with 113 additions and 208 deletions
+83 -105
View File
@@ -553,13 +553,12 @@ class MainWindow(QMainWindow):
"""Генерирует план эксперимента"""
all_factors = self._get_factors_from_table()
factors = get_active_factors(all_factors)
# Выбираем только те факторы, шаг которых не равен нулю
i_factors = get_inactive_factors(all_factors)
# Отдельно сохраняем неактивные факторы
if len(factors) == 0:
if not factors:
QMessageBox.warning(self, "Предупреждение", "Добавьте хотя бы один фактор!")
return
try:
design = generate_factorial_design(
factors=factors,
@@ -567,74 +566,13 @@ class MainWindow(QMainWindow):
randomize=self.randomize_check.isChecked()
)
self.generated_design = design
n_exp = len(design)
n_factors = len(factors)
n_i_factors = len(i_factors)
solvent_name = self.exp_solvent.text()
total_volume = self.exp_total_volume.value()
solvent_unit = self.exp_volume_unit.currentText()
self.design_matrix.setRowCount(n_exp)
self.design_matrix.setColumnCount(n_factors + 4)
headers = [f['name'] for f in factors] + [f['name'] for f in i_factors] + [solvent_name] +["Тип"] +["Отклик"]
self.design_matrix.setHorizontalHeaderLabels(headers)
for exp_idx, exp in enumerate(design):
solvent = convert_units(total_volume,solvent_unit)
for f_idx in range(n_factors):
key = f"Фактор_{f_idx+1}"
if key not in exp:
continue
value = exp[key]['natural']
unit = factors[f_idx]['unit']
solvent -= convert_units(value,unit)
display = self._format_number(value)
if unit:
display += f" {unit}"
item = QTableWidgetItem(display)
if exp.get('is_center', False):
item.setBackground(QColor(255, 255, 200))
self.design_matrix.setItem(exp_idx, f_idx, item)
if n_i_factors>0:
for f_idx in range(n_i_factors):
value = i_factors[f_idx]['center']
unit = i_factors[f_idx]['unit']
display = self._format_number(value)
if unit:
display += f" {unit}"
item = QTableWidgetItem(display)
self._fill_design_matrix(design, factors, i_factors)
item.setBackground(QColor(255, 255, 200))
self.design_matrix.setItem(exp_idx, n_factors + f_idx, item)
solvent = convert_units(solvent, "мкл", solvent_unit)
display = self._format_number(solvent)
if solvent_unit:
display += f" {solvent_unit}"
item = QTableWidgetItem(display)
self.design_matrix.setItem(exp_idx, n_factors+n_i_factors, item)
if exp.get('is_center', False):
type_item = QTableWidgetItem(f"Центр #{exp['center_num']}")
type_item.setBackground(QColor(255, 255, 200))
else:
type_item = QTableWidgetItem("Факторная")
self.design_matrix.setItem(exp_idx, n_factors+n_i_factors + 1, type_item)
self.design_matrix.resizeColumnsToContents()
n_factorial = 2 ** n_factors
n_center = self.center_points_spin.value()
self.design_info.setText(
f"📊 Факторных точек: {n_factorial}, Центральных: {n_center}, Всего: {n_exp}"
)
self.export_csv_btn.setEnabled(True)
self._setup_results_table(n_exp)
QMessageBox.information(self, "Успех",
f"Сгенерирован план для {n_factors} факторов ({n_exp} опытов)")
QMessageBox.information(self, "Успех", f"Сгенерирован план для {len(factors)} факторов ({len(design)} опытов)")
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка генерации плана: {str(e)}")
def _setup_results_table(self, n_experiments: int):
"""Настраивает таблицу результатов для ввода данных"""
@@ -978,47 +916,19 @@ class MainWindow(QMainWindow):
"""Обновляет отображение матрицы планирования"""
if not self.generated_design:
return
factors = self._get_factors_from_table()
all_factors = self._get_factors_from_table()
factors = get_active_factors(all_factors)
i_factors = get_inactive_factors(all_factors)
self._fill_design_matrix(self.generated_design, factors, i_factors)
n_exp = len(self.generated_design)
n_factors = len(factors)
self.design_matrix.setRowCount(n_exp)
self.design_matrix.setColumnCount(n_factors + 2)
headers = [""] + [f['name'] for f in factors] + ["Тип"]
self.design_matrix.setHorizontalHeaderLabels(headers)
for exp_idx, exp in enumerate(self.generated_design):
self.design_matrix.setItem(exp_idx, 0, QTableWidgetItem(str(exp_idx + 1)))
for f_idx in range(n_factors):
key = f"Фактор_{f_idx + 1}"
if key not in exp:
continue
value = exp[key]['natural']
unit = factors[f_idx]['unit']
display = self._format_number(value)
if unit:
display += f" {unit}"
item = QTableWidgetItem(display)
if exp.get('is_center', False):
item.setBackground(QColor(255, 255, 200))
self.design_matrix.setItem(exp_idx, f_idx + 1, item)
if exp.get('is_center', False):
type_item = QTableWidgetItem(f"Центр #{exp['center_num']}")
type_item.setBackground(QColor(255, 255, 200))
else:
type_item = QTableWidgetItem("Факторная")
self.design_matrix.setItem(exp_idx, n_factors + 1, type_item)
self.design_matrix.resizeColumnsToContents()
if hasattr(self, 'export_csv_btn'):
self.export_csv_btn.setEnabled(True)
n_factorial = 2 ** n_factors
n_center = self.center_points_spin.value()
self.design_info.setText(
@@ -1027,6 +937,74 @@ class MainWindow(QMainWindow):
self._setup_results_table(n_exp)
# ========== ВСПОМОГАТЕЛЬНЫЕ МЕТОДЫ ==========
def _fill_design_matrix(self, design, factors, i_factors):
"""Заполняет матрицу планирования (общая логика)"""
n_exp = len(design)
n_factors = len(factors)
n_i_factors = len(i_factors)
solvent_name = self.exp_solvent.text()
total_volume = self.exp_total_volume.value()
solvent_unit = self.exp_volume_unit.currentText()
self.design_matrix.setRowCount(n_exp)
self.design_matrix.setColumnCount(n_factors + n_i_factors + 3)
headers = [f['name'] for f in factors] + [f['name'] for f in i_factors] + [solvent_name] + ["Тип"] + ["Отклик"]
self.design_matrix.setHorizontalHeaderLabels(headers)
for exp_idx, exp in enumerate(design):
remaining = convert_units(total_volume, solvent_unit)
# Активные факторы
for f_idx in range(n_factors):
value = exp[f"Фактор_{f_idx+1}"]['natural']
unit = factors[f_idx]['unit']
remaining -= convert_units(value, unit)
item = self._create_item(value, unit, exp.get('is_center', False))
if value == factors[f_idx]['high']:
item.setBackground(QColor(200, 250, 200))
elif value ==factors[f_idx]['low']:
item.setBackground(QColor(250, 200, 200))
else:
item.setBackground(QColor(230, 230, 230))
self.design_matrix.setItem(exp_idx, f_idx, item)
# Неактивные факторы
for f_idx in range(n_i_factors):
value = i_factors[f_idx]['center']
unit = i_factors[f_idx]['unit']
remaining -= convert_units(value, unit)
item = self._create_item(value, unit, True)
item.setBackground(QColor(230, 230, 230))
self.design_matrix.setItem(exp_idx, n_factors + f_idx, item)
# Растворитель
remaining = convert_units(remaining, 'мкл', solvent_unit)
item = self._create_item(remaining, solvent_unit, False)
item.setBackground(QColor(200, 200, 255))
self.design_matrix.setItem(exp_idx, n_factors + n_i_factors, item)
# Тип опыта
type_item = QTableWidgetItem(f"Центр #{exp['center_num']}" if exp.get('is_center') else "Факторная")
if exp.get('is_center'):
type_item.setBackground(QColor(200, 200, 200))
self.design_matrix.setItem(exp_idx, n_factors + n_i_factors + 1, type_item)
# Отклик
self.design_matrix.setItem(exp_idx, n_factors + n_i_factors + 2, QTableWidgetItem(""))
self.design_matrix.resizeColumnsToContents()
def _create_item(self, value, unit, is_center):
"""Создаёт QTableWidgetItem с форматированием"""
display = self._format_number(value)
if unit:
display += f" {unit}"
item = QTableWidgetItem(display)
if is_center:
item.setBackground(QColor(255, 255, 200))
return item
def _format_number(self, value: float) -> str:
"""Форматирует число для отображения"""