Добавленна поддержка отображения, сохранинения, и загрузки растворителя во вкладке факторнго эксперимента. Убрана галочка рАндомизировать по умолчанию
This commit is contained in:
Binary file not shown.
@@ -7,7 +7,13 @@ from dataclasses import dataclass, asdict
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
VERSION="alpha_0.3"
|
||||||
|
"""
|
||||||
|
Условно
|
||||||
|
0.1 - Разработка калькулятора сред
|
||||||
|
0.2 - Разработка факторов эксперимента
|
||||||
|
0.3 - разработка матрицы планирования
|
||||||
|
"""
|
||||||
@dataclass
|
@dataclass
|
||||||
class ReagentData:
|
class ReagentData:
|
||||||
"""Данные реагента"""
|
"""Данные реагента"""
|
||||||
@@ -111,7 +117,7 @@ class ProjectData:
|
|||||||
project_name: str
|
project_name: str
|
||||||
created_at: str
|
created_at: str
|
||||||
modified_at: str
|
modified_at: str
|
||||||
version: str = "1.0"
|
version: str = VERSION
|
||||||
|
|
||||||
# Данные калькулятора сред
|
# Данные калькулятора сред
|
||||||
medium_total_volume: float = 1000.0
|
medium_total_volume: float = 1000.0
|
||||||
@@ -120,6 +126,9 @@ class ProjectData:
|
|||||||
medium_reagents: List[ReagentData] = None
|
medium_reagents: List[ReagentData] = None
|
||||||
|
|
||||||
# Данные эксперимента
|
# Данные эксперимента
|
||||||
|
experiment_total_volume: float = 1000.0
|
||||||
|
experiment_volume_unit: str = "мл"
|
||||||
|
experiment_solvent: str = "Вода"
|
||||||
experiment_factors: List[FactorData] = None
|
experiment_factors: List[FactorData] = None
|
||||||
experiment_responses: List[ResponseData] = None
|
experiment_responses: List[ResponseData] = None
|
||||||
experiment_center_points: int = 3
|
experiment_center_points: int = 3
|
||||||
@@ -150,6 +159,9 @@ class ProjectData:
|
|||||||
'reagents': [r.to_dict() for r in self.medium_reagents]
|
'reagents': [r.to_dict() for r in self.medium_reagents]
|
||||||
},
|
},
|
||||||
'experiment': {
|
'experiment': {
|
||||||
|
'total_volume': self.medium_total_volume,
|
||||||
|
'volume_unit': self.medium_volume_unit,
|
||||||
|
'solvent': self.medium_solvent,
|
||||||
'factors': [f.to_dict() for f in self.experiment_factors],
|
'factors': [f.to_dict() for f in self.experiment_factors],
|
||||||
'responses': [r.to_dict() for r in self.experiment_responses],
|
'responses': [r.to_dict() for r in self.experiment_responses],
|
||||||
'center_points': self.experiment_center_points,
|
'center_points': self.experiment_center_points,
|
||||||
@@ -175,6 +187,9 @@ class ProjectData:
|
|||||||
medium_volume_unit=medium.get('volume_unit', 'мл'),
|
medium_volume_unit=medium.get('volume_unit', 'мл'),
|
||||||
medium_solvent=medium.get('solvent', 'Вода'),
|
medium_solvent=medium.get('solvent', 'Вода'),
|
||||||
medium_reagents=[ReagentData.from_dict(r) for r in medium.get('reagents', [])],
|
medium_reagents=[ReagentData.from_dict(r) for r in medium.get('reagents', [])],
|
||||||
|
experiment_total_volume=experiment.get('total_volume', 1000.0),
|
||||||
|
experiment_volume_unit=experiment.get('volume_unit', 'мл'),
|
||||||
|
experiment_solvent=experiment.get('solvent', 'Вода'),
|
||||||
experiment_factors=[FactorData.from_dict(f) for f in experiment.get('factors', [])],
|
experiment_factors=[FactorData.from_dict(f) for f in experiment.get('factors', [])],
|
||||||
experiment_responses=[ResponseData.from_dict(r) for r in experiment.get('responses', [])],
|
experiment_responses=[ResponseData.from_dict(r) for r in experiment.get('responses', [])],
|
||||||
experiment_center_points=experiment.get('center_points', 3),
|
experiment_center_points=experiment.get('center_points', 3),
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
"""
|
"""
|
||||||
Единый графический интерфейс для калькулятора сред и DoE
|
Единый графический интерфейс для калькулятора сред и DoE
|
||||||
"""
|
"""
|
||||||
from theme import Colors, Fonts, Spacing, ButtonStyles, get_full_stylesheet, apply_theme
|
from theme import Colors, Fonts, Spacing, ButtonStyles, get_full_stylesheet, apply_theme, TitleStyles
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Dict, Optional
|
from typing import List, Dict, Optional
|
||||||
|
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
QTabWidget, QGroupBox, QLabel, QPushButton, QTableWidget,
|
QTabWidget, QGroupBox, QLabel, QPushButton, QTableWidget,
|
||||||
@@ -86,12 +85,8 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Заголовок
|
# Заголовок
|
||||||
title = QLabel("Цифровой помощник биохимика")
|
title = QLabel("Цифровой помощник биохимика")
|
||||||
title_font = QFont()
|
title.setObjectName("mainTitle") # Стиль подтянется из theme
|
||||||
title_font.setPointSize(18)
|
|
||||||
title_font.setBold(True)
|
|
||||||
title.setFont(title_font)
|
|
||||||
title.setAlignment(Qt.AlignCenter)
|
title.setAlignment(Qt.AlignCenter)
|
||||||
title.setStyleSheet("color: #2c3e50; padding: 10px;")
|
|
||||||
layout.addWidget(title)
|
layout.addWidget(title)
|
||||||
|
|
||||||
# Вкладки
|
# Вкладки
|
||||||
@@ -275,7 +270,7 @@ class MainWindow(QMainWindow):
|
|||||||
)
|
)
|
||||||
self.info_label.setText(solvent_text)
|
self.info_label.setText(solvent_text)
|
||||||
self.info_label.setStyleSheet("background-color: #d5f5e3; padding: 8px; border-radius: 5px;")
|
self.info_label.setStyleSheet("background-color: #d5f5e3; padding: 8px; border-radius: 5px;")
|
||||||
|
print(result)
|
||||||
# Сохраняем результаты для передачи в DoE
|
# Сохраняем результаты для передачи в DoE
|
||||||
self.last_medium_result = result
|
self.last_medium_result = result
|
||||||
|
|
||||||
@@ -332,19 +327,43 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Настройки эксперимента
|
# Настройки эксперимента
|
||||||
settings_box = QGroupBox("Настройки эксперимента")
|
settings_box = QGroupBox("Настройки эксперимента")
|
||||||
settings_layout = QHBoxLayout()
|
settings_layout = QVBoxLayout()
|
||||||
|
|
||||||
settings_layout.addWidget(QLabel("Центральных точек:"))
|
# Параметры среды (из калькулятора)
|
||||||
|
env_layout = QHBoxLayout()
|
||||||
|
env_layout.addWidget(QLabel("Общий объём:"))
|
||||||
|
self.exp_total_volume = QDoubleSpinBox()
|
||||||
|
self.exp_total_volume.setRange(0.001, 1000000)
|
||||||
|
self.exp_total_volume.setValue(100)
|
||||||
|
self.exp_total_volume.setSuffix(" ")
|
||||||
|
env_layout.addWidget(self.exp_total_volume)
|
||||||
|
|
||||||
|
self.exp_volume_unit = QComboBox()
|
||||||
|
self.exp_volume_unit.addItems(["мл", "л", "мкл", "нл"])
|
||||||
|
self.exp_volume_unit.setCurrentText("мл")
|
||||||
|
env_layout.addWidget(self.exp_volume_unit)
|
||||||
|
|
||||||
|
env_layout.addSpacing(20)
|
||||||
|
env_layout.addWidget(QLabel("Растворитель:"))
|
||||||
|
self.exp_solvent = QLineEdit("Вода")
|
||||||
|
env_layout.addWidget(self.exp_solvent)
|
||||||
|
env_layout.addStretch()
|
||||||
|
settings_layout.addLayout(env_layout)
|
||||||
|
|
||||||
|
# Настройки эксперимента
|
||||||
|
exp_layout = QHBoxLayout()
|
||||||
|
exp_layout.addWidget(QLabel("Центральных точек:"))
|
||||||
self.center_points_spin = QSpinBox()
|
self.center_points_spin = QSpinBox()
|
||||||
self.center_points_spin.setRange(0, 10)
|
self.center_points_spin.setRange(0, 10)
|
||||||
self.center_points_spin.setValue(3)
|
self.center_points_spin.setValue(3)
|
||||||
settings_layout.addWidget(self.center_points_spin)
|
exp_layout.addWidget(self.center_points_spin)
|
||||||
settings_layout.addSpacing(20)
|
exp_layout.addSpacing(20)
|
||||||
|
|
||||||
self.randomize_check = QCheckBox("Рэндомизировать порядок")
|
self.randomize_check = QCheckBox("Рандомизировать порядок")
|
||||||
self.randomize_check.setChecked(True)
|
self.randomize_check.setChecked(False)
|
||||||
settings_layout.addWidget(self.randomize_check)
|
exp_layout.addWidget(self.randomize_check)
|
||||||
settings_layout.addStretch()
|
exp_layout.addStretch()
|
||||||
|
settings_layout.addLayout(exp_layout)
|
||||||
|
|
||||||
settings_box.setLayout(settings_layout)
|
settings_box.setLayout(settings_layout)
|
||||||
layout.addWidget(settings_box)
|
layout.addWidget(settings_box)
|
||||||
@@ -415,6 +434,10 @@ class MainWindow(QMainWindow):
|
|||||||
# Очищаем таблицу факторов
|
# Очищаем таблицу факторов
|
||||||
self.factors_table.setRowCount(0)
|
self.factors_table.setRowCount(0)
|
||||||
|
|
||||||
|
|
||||||
|
self.exp_total_volume.setValue(result['total_volume'])
|
||||||
|
self.exp_volume_unit.setCurrentText(result['total_unit'])
|
||||||
|
self.exp_solvent.setText(result['solvent_name'])
|
||||||
for reagent in result['reagents']:
|
for reagent in result['reagents']:
|
||||||
name = reagent['name']
|
name = reagent['name']
|
||||||
if reagent.get('dilution_factor', 1.0) != 1.0:
|
if reagent.get('dilution_factor', 1.0) != 1.0:
|
||||||
@@ -906,7 +929,12 @@ class MainWindow(QMainWindow):
|
|||||||
self.reagents_table.setItem(row, 4, QTableWidgetItem(str(reagent.dilution_factor)))
|
self.reagents_table.setItem(row, 4, QTableWidgetItem(str(reagent.dilution_factor)))
|
||||||
self.reagents_table.setItem(row, 5, QTableWidgetItem(""))
|
self.reagents_table.setItem(row, 5, QTableWidgetItem(""))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Применяем данные факторов эксперимента
|
# Применяем данные факторов эксперимента
|
||||||
|
self.exp_total_volume.setValue(project.experiment_total_volume)
|
||||||
|
self.exp_volume_unit.setCurrentText(project.experiment_volume_unit)
|
||||||
|
self.exp_solvent.setText(project.experiment_solvent)
|
||||||
self.factors_table.setRowCount(0)
|
self.factors_table.setRowCount(0)
|
||||||
for factor in project.experiment_factors:
|
for factor in project.experiment_factors:
|
||||||
if factor.percentage is not None:
|
if factor.percentage is not None:
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from PyQt5.QtWidgets import QApplication
|
|||||||
from gui import MainWindow
|
from gui import MainWindow
|
||||||
from theme import Fonts, setup_emoji_support
|
from theme import Fonts, setup_emoji_support
|
||||||
|
|
||||||
|
|
||||||
# Добавляем текущую директорию в путь
|
# Добавляем текущую директорию в путь
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
sys.path.insert(0, os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Colors:
|
|||||||
"""Цветовая палитра приложения"""
|
"""Цветовая палитра приложения"""
|
||||||
|
|
||||||
# Основные цвета (Primary)
|
# Основные цвета (Primary)
|
||||||
PRIMARY = "#999999" # Синий - основной акцент
|
PRIMARY = "#3498db" # Синий - основной акцент
|
||||||
PRIMARY_DARK = "#777777" # Тёмно-синий (наведение)
|
PRIMARY_DARK = "#777777" # Тёмно-синий (наведение)
|
||||||
PRIMARY_LIGHT = "#5dade2" # Светло-синий
|
PRIMARY_LIGHT = "#5dade2" # Светло-синий
|
||||||
PRIMARY_BG = "#ebf5fb" # Фоновый для primary элементов
|
PRIMARY_BG = "#ebf5fb" # Фоновый для primary элементов
|
||||||
@@ -69,6 +69,9 @@ class Colors:
|
|||||||
BORDER_DEFAULT = GRAY_400
|
BORDER_DEFAULT = GRAY_400
|
||||||
BORDER_DARK = GRAY_600
|
BORDER_DARK = GRAY_600
|
||||||
|
|
||||||
|
# Цвет для заголовка
|
||||||
|
TITLE_COLOR = "#2c3e50"
|
||||||
|
|
||||||
# Прозрачность
|
# Прозрачность
|
||||||
TRANSPARENT = "transparent"
|
TRANSPARENT = "transparent"
|
||||||
OVERLAY = "rgba(0, 0, 0, 0.5)"
|
OVERLAY = "rgba(0, 0, 0, 0.5)"
|
||||||
@@ -100,7 +103,7 @@ class Fonts:
|
|||||||
def get_title_font(cls):
|
def get_title_font(cls):
|
||||||
"""Возвращает шрифт для заголовков"""
|
"""Возвращает шрифт для заголовков"""
|
||||||
font = QFont(cls.FAMILY_PRIMARY.split(',')[0])
|
font = QFont(cls.FAMILY_PRIMARY.split(',')[0])
|
||||||
font.setPointSize(cls.SIZE_XLARGE)
|
font.setPointSize(cls.SIZE_XXLARGE)
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
return font
|
return font
|
||||||
|
|
||||||
@@ -192,6 +195,21 @@ class Spacing:
|
|||||||
BORDER_RADIUS_LG = 8
|
BORDER_RADIUS_LG = 8
|
||||||
BORDER_RADIUS_XL = 12
|
BORDER_RADIUS_XL = 12
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ========== СТИЛЬ ЗАГОЛОВКА ==========
|
||||||
|
|
||||||
|
class TitleStyles:
|
||||||
|
@staticmethod
|
||||||
|
def main_title():
|
||||||
|
return f"""
|
||||||
|
color: {Colors.TITLE_COLOR};
|
||||||
|
padding: {Spacing.XL}px;
|
||||||
|
font-size: {Fonts.SIZE_XLARGE}px;
|
||||||
|
font-weight: {Fonts.WEIGHT_BOLD};
|
||||||
|
"""
|
||||||
|
|
||||||
# ========== СТИЛИ КНОПОК ==========
|
# ========== СТИЛИ КНОПОК ==========
|
||||||
class ButtonStyles:
|
class ButtonStyles:
|
||||||
"""Стили для разных типов кнопок"""
|
"""Стили для разных типов кнопок"""
|
||||||
@@ -464,9 +482,10 @@ class GroupBoxStyles:
|
|||||||
font-size: {Fonts.SIZE_MEDIUM}px;
|
font-size: {Fonts.SIZE_MEDIUM}px;
|
||||||
}}
|
}}
|
||||||
QGroupBox::title {{
|
QGroupBox::title {{
|
||||||
|
|
||||||
subcontrol-origin: margin;
|
subcontrol-origin: margin;
|
||||||
left: {Spacing.LG}px;
|
left: {Spacing.LG}px;
|
||||||
padding: 0 {Spacing.MD}px;
|
padding: 10 {Spacing.MD}px;
|
||||||
color: {Colors.INFO};
|
color: {Colors.INFO};
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
@@ -485,7 +504,7 @@ class GroupBoxStyles:
|
|||||||
QGroupBox::title {{
|
QGroupBox::title {{
|
||||||
subcontrol-origin: margin;
|
subcontrol-origin: margin;
|
||||||
left: {Spacing.LG}px;
|
left: {Spacing.LG}px;
|
||||||
padding: 0 {Spacing.MD}px;
|
padding: 10 {Spacing.MD}px;
|
||||||
color: {Colors.PRIMARY};
|
color: {Colors.PRIMARY};
|
||||||
}}
|
}}
|
||||||
"""
|
"""
|
||||||
@@ -566,8 +585,29 @@ def get_full_stylesheet():
|
|||||||
"""
|
"""
|
||||||
Возвращает полную таблицу стилей для приложения
|
Возвращает полную таблицу стилей для приложения
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return f"""
|
return f"""
|
||||||
|
/* СТИЛИ ДЛЯ ВСЕХ КНОПОК ПО УМОЛЧАНИЮ */
|
||||||
|
QPushButton {{
|
||||||
|
background-color: {Colors.PRIMARY};
|
||||||
|
color: {Colors.TEXT_ON_PRIMARY};
|
||||||
|
border: none;
|
||||||
|
border-radius: {Spacing.BORDER_RADIUS_MD}px;
|
||||||
|
padding: {Spacing.SM}px {Spacing.LG}px;
|
||||||
|
font-weight: {Fonts.WEIGHT_SEMIBOLD};
|
||||||
|
font-size: {Fonts.SIZE_NORMAL}px;
|
||||||
|
}}
|
||||||
|
QPushButton:hover {{
|
||||||
|
background-color: {Colors.PRIMARY_LIGHT};
|
||||||
|
}}
|
||||||
|
QPushButton:pressed {{
|
||||||
|
background-color: {Colors.PRIMARY_DARK};
|
||||||
|
}}
|
||||||
|
|
||||||
/* Глобальные стили */
|
/* Глобальные стили */
|
||||||
|
QLabel#mainTitle {{
|
||||||
|
{TitleStyles.main_title()}
|
||||||
|
}}
|
||||||
QMainWindow {{
|
QMainWindow {{
|
||||||
background-color: {Colors.GRAY_200};
|
background-color: {Colors.GRAY_200};
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user