feat: добавил отображение графиков
This commit is contained in:
parent
ac8c128484
commit
dba7e3c235
@ -1,4 +1,4 @@
|
||||
{
|
||||
"trace_storage_path": "/home/andrei/Desktop/bla",
|
||||
"monitor_update_period": 0.1
|
||||
"monitor_update_period": 100
|
||||
}
|
148
src/base/base.py
Normal file
148
src/base/base.py
Normal file
@ -0,0 +1,148 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Optional, Union
|
||||
|
||||
import pandas as pd
|
||||
from PyQt5.QtCore import QThread, QObject, QTimer
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
|
||||
class BaseMediator:
|
||||
def __init__(self,
|
||||
monitor: BaseDirectoryMonitor,
|
||||
converter: BaseDataConverter,
|
||||
plot: BasePlotWidget,
|
||||
controller: BaseController):
|
||||
self._monitor = monitor
|
||||
self._monitor.mediator = self
|
||||
self._converter = converter
|
||||
self._converter.mediator = self
|
||||
self._plot = plot
|
||||
self._plot.mediator = self
|
||||
self._controller = controller
|
||||
|
||||
def notify(self,
|
||||
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget],
|
||||
data: Union[list[str], list[pd.DataFrame], list[QWidget]]):
|
||||
...
|
||||
|
||||
|
||||
class BaseDirectoryMonitor:
|
||||
|
||||
update_timer = QTimer()
|
||||
|
||||
def __init__(self,
|
||||
directory_path: str,
|
||||
update_time: int,
|
||||
mediator: Optional[BaseMediator] = None):
|
||||
super().__init__()
|
||||
|
||||
self._directory_path = directory_path
|
||||
self._update_time = update_time
|
||||
self._mediator = mediator
|
||||
|
||||
self._files: list[str] = []
|
||||
|
||||
self._init_state()
|
||||
|
||||
@property
|
||||
def directory_path(self) -> str:
|
||||
return self._directory_path
|
||||
|
||||
@property
|
||||
def update_time(self) -> int:
|
||||
return self._update_time
|
||||
|
||||
@property
|
||||
def files(self) -> list[str]:
|
||||
return self._files
|
||||
|
||||
@property
|
||||
def mediator(self) -> BaseMediator:
|
||||
return self._mediator
|
||||
|
||||
@mediator.setter
|
||||
def mediator(self, mediator: BaseMediator) -> None:
|
||||
self._mediator = mediator
|
||||
|
||||
def _init_state(self):
|
||||
files = os.listdir(self._directory_path)
|
||||
self._files = files
|
||||
|
||||
def start(self):
|
||||
self.update_timer.start(self._update_time)
|
||||
|
||||
class BaseDataConverter:
|
||||
def __init__(self, mediator: Optional[BaseMediator] = None):
|
||||
self._mediator = mediator
|
||||
|
||||
@property
|
||||
def mediator(self) -> BaseMediator:
|
||||
return self._mediator
|
||||
|
||||
@mediator.setter
|
||||
def mediator(self, mediator: BaseMediator) -> None:
|
||||
self._mediator = mediator
|
||||
|
||||
def convert_data(self, files: list[str]) -> None:
|
||||
...
|
||||
|
||||
|
||||
class BasePlotWidget:
|
||||
def __init__(self, mediator: Optional[BaseMediator] = None):
|
||||
super().__init__()
|
||||
self._mediator = mediator
|
||||
|
||||
# "Electrode Position": ["Rotor Position, mm ME", "Rotor Position, mm FE"],
|
||||
# "Electrode Speed": ["Rotor Speed, mm/s ME", "Rotor Speed, mm/s FE"]
|
||||
|
||||
self._plot_channels = {
|
||||
"Electrode Force": [
|
||||
{
|
||||
"name": "Electrode Force, N ME",
|
||||
"pen": 'r'
|
||||
},
|
||||
{
|
||||
"name":"Electrode Force, N FE",
|
||||
"pen": 'w'
|
||||
},
|
||||
],
|
||||
"Electrode Position": [
|
||||
{
|
||||
"name": "Rotor Position, mm ME",
|
||||
"pen": 'r'
|
||||
},
|
||||
{
|
||||
"name": "Rotor Position, mm FE",
|
||||
"pen": 'w'
|
||||
},
|
||||
],
|
||||
"Electrode Speed": [
|
||||
{
|
||||
"name": "Rotor Speed, mm/s ME",
|
||||
"pen": 'r'
|
||||
},
|
||||
{
|
||||
"name": "Rotor Speed, mm/s FE",
|
||||
"pen": 'w'
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@property
|
||||
def mediator(self) -> BaseMediator:
|
||||
return self._mediator
|
||||
|
||||
@mediator.setter
|
||||
def mediator(self, mediator: BaseMediator) -> None:
|
||||
self._mediator = mediator
|
||||
|
||||
def build(self, data: list[pd.DataFrame]) -> list[QWidget]:
|
||||
...
|
||||
|
||||
|
||||
class BaseController(QObject):
|
||||
|
||||
def send_widgets(self, widgets: list[QWidget]) -> None:
|
||||
...
|
@ -1,76 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Optional, Union
|
||||
|
||||
import pandas as pd
|
||||
from PyQt5.QtCore import QThread
|
||||
|
||||
|
||||
class BaseMediator:
|
||||
def __init__(self,
|
||||
monitor: BaseDirectoryMonitor,
|
||||
converter: BaseDataConverter):
|
||||
self._monitor = monitor
|
||||
self._monitor.mediator = self
|
||||
self._converter = converter
|
||||
self._converter.mediator = self
|
||||
|
||||
def notify(self,
|
||||
source: Union[BaseDirectoryMonitor, BaseDataConverter],
|
||||
data: Union[list[str], list[pd.DataFrame]]):
|
||||
...
|
||||
|
||||
|
||||
class BaseDirectoryMonitor(QThread):
|
||||
def __init__(self,
|
||||
directory_path: str,
|
||||
update_time: int,
|
||||
mediator: Optional[BaseMediator] = None):
|
||||
super().__init__()
|
||||
|
||||
self._directory_path = directory_path
|
||||
self._update_time = update_time
|
||||
self._mediator = mediator
|
||||
|
||||
self._files: list[str] = []
|
||||
|
||||
@property
|
||||
def directory_path(self) -> str:
|
||||
return self._directory_path
|
||||
|
||||
@property
|
||||
def update_time(self) -> int:
|
||||
return self._update_time
|
||||
|
||||
@property
|
||||
def files(self) -> list[str]:
|
||||
return self._files
|
||||
|
||||
@property
|
||||
def mediator(self) -> BaseMediator:
|
||||
return self._mediator
|
||||
|
||||
@mediator.setter
|
||||
def mediator(self, mediator: BaseMediator) -> None:
|
||||
self._mediator = mediator
|
||||
|
||||
def _init_state(self):
|
||||
files = os.listdir(self._directory_path)
|
||||
self._files = files
|
||||
|
||||
|
||||
class BaseDataConverter:
|
||||
def __init__(self, mediator: Optional[BaseMediator] = None):
|
||||
self._mediator = mediator
|
||||
|
||||
@property
|
||||
def mediator(self) -> BaseMediator:
|
||||
return self._mediator
|
||||
|
||||
@mediator.setter
|
||||
def mediator(self, mediator: BaseMediator) -> None:
|
||||
self._mediator = mediator
|
||||
|
||||
def convert_data(self, files: list[str]) -> None:
|
||||
...
|
12
src/controller/controller.py
Normal file
12
src/controller/controller.py
Normal file
@ -0,0 +1,12 @@
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
from base.base import BaseController
|
||||
|
||||
|
||||
class Controller(BaseController):
|
||||
|
||||
signal_widgets = pyqtSignal(list)
|
||||
|
||||
def send_widgets(self, widgets: list[QWidget]) -> None:
|
||||
self.signal_widgets.emit(widgets)
|
@ -3,7 +3,7 @@ import pandas as pd
|
||||
#FIXME: костыль для выключения предупреждения "replace deprecated". Потом надо поправить.
|
||||
pd.set_option('future.no_silent_downcasting', True)
|
||||
|
||||
from controller.base import BaseDataConverter
|
||||
from base.base import BaseDataConverter
|
||||
|
||||
|
||||
class DataConverter(BaseDataConverter):
|
||||
|
@ -1,19 +1,21 @@
|
||||
import pandas as pd
|
||||
|
||||
from typing import Union
|
||||
from loguru import logger
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from controller.base import BaseMediator, BaseDirectoryMonitor, BaseDataConverter
|
||||
from base.base import BaseMediator, BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget
|
||||
|
||||
|
||||
class Mediator(BaseMediator):
|
||||
|
||||
def notify(self,
|
||||
source: Union[BaseDirectoryMonitor, BaseDataConverter],
|
||||
data: Union[list[str], list[pd.DataFrame]]):
|
||||
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget],
|
||||
data: Union[list[str], list[pd.DataFrame], list[QWidget]]):
|
||||
if issubclass(source.__class__, BaseDirectoryMonitor):
|
||||
self._converter.convert_data(data)
|
||||
|
||||
if issubclass(source.__class__, BaseDataConverter):
|
||||
# TODO: отправить датафреймы в конструктор графиков
|
||||
logger.info(data)
|
||||
self._plot.build(data)
|
||||
|
||||
if issubclass(source.__class__, BasePlotWidget):
|
||||
self._controller.send_widgets(data)
|
||||
|
@ -3,23 +3,26 @@ import os
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from controller.base import BaseDirectoryMonitor
|
||||
from base.base import BaseDirectoryMonitor
|
||||
|
||||
|
||||
class DirectoryMonitor(BaseDirectoryMonitor):
|
||||
|
||||
def run(self):
|
||||
self._init_state()
|
||||
logger.info("Monitor initiated")
|
||||
def _init_state(self):
|
||||
files = os.listdir(self._directory_path)
|
||||
self._files = files
|
||||
|
||||
self.update_timer.timeout.connect(self._monitor)
|
||||
logger.info("Monitor initiated!")
|
||||
|
||||
def _monitor(self):
|
||||
files = os.listdir(self._directory_path)
|
||||
new_files = sorted(list(map(lambda x: os.path.join(self._directory_path, x),
|
||||
filter(lambda x: x not in self._files, files))))
|
||||
if new_files:
|
||||
logger.info(f"New files detected: {new_files}")
|
||||
self._mediator.notify(self, new_files)
|
||||
self._files = files
|
||||
if not files:
|
||||
self._files = []
|
||||
|
||||
while True:
|
||||
files = os.listdir(self._directory_path)
|
||||
new_files = sorted(list(map(lambda x: os.path.join(self._directory_path, x),
|
||||
filter(lambda x: x not in self._files, files))))
|
||||
if new_files:
|
||||
logger.info(f"New files detected: {new_files}")
|
||||
self._mediator.notify(self, new_files)
|
||||
self._files = files
|
||||
if not files:
|
||||
self._files = []
|
||||
sleep(self._update_time)
|
||||
|
@ -6,4 +6,13 @@ from gui.widgets import mainForm
|
||||
class MainWindow(QtWidgets.QWidget, mainForm.Ui_Form):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setupUi(self)
|
||||
self.setupUi(self)
|
||||
|
||||
def show_plot_tabs(self, plot_widgets: list[QtWidgets.QWidget]) -> None:
|
||||
for plot_widget in plot_widgets:
|
||||
tab = QtWidgets.QWidget()
|
||||
grid = QtWidgets.QGridLayout()
|
||||
grid.addWidget(plot_widget)
|
||||
tab.setLayout(grid)
|
||||
self.tabWidget.addTab(tab, "text")
|
||||
self.tabWidget.setCurrentWidget(tab)
|
||||
|
33
src/gui/widgets/plot.py
Normal file
33
src/gui/widgets/plot.py
Normal file
@ -0,0 +1,33 @@
|
||||
import pandas as pd
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout
|
||||
import pyqtgraph as pg
|
||||
|
||||
from base.base import BasePlotWidget
|
||||
|
||||
|
||||
class PlotWidget(BasePlotWidget):
|
||||
|
||||
def _create_widget(self, dataframe: pd.DataFrame) -> QWidget:
|
||||
widget = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
|
||||
time_axis = dataframe["time"]
|
||||
|
||||
for channel, signals in self._plot_channels.items():
|
||||
plot_widget = pg.PlotWidget(title=channel)
|
||||
plot_widget.showGrid(x=True, y=True)
|
||||
legend = pg.LegendItem((80, 60), offset=(70, 20))
|
||||
legend.setParentItem(plot_widget.graphicsItem())
|
||||
|
||||
for signal in signals:
|
||||
plot = plot_widget.plot(time_axis, dataframe[signal["name"]], pen=signal["pen"])
|
||||
legend.addItem(plot, signal["name"])
|
||||
|
||||
layout.addWidget(plot_widget)
|
||||
|
||||
widget.setLayout(layout)
|
||||
return widget
|
||||
|
||||
def build(self, data: list[pd.DataFrame]) -> None:
|
||||
widgets = [self._create_widget(data_sample) for data_sample in data]
|
||||
self._mediator.notify(self, widgets)
|
11
src/main.py
11
src/main.py
@ -8,6 +8,8 @@ from cfg.schema import ConfigSchema
|
||||
from controller.monitor import DirectoryMonitor
|
||||
from controller.mediator import Mediator
|
||||
from controller.converter import DataConverter
|
||||
from gui.widgets import plot
|
||||
from controller.controller import Controller
|
||||
|
||||
|
||||
def read_json(filepath: str) -> dict:
|
||||
@ -24,12 +26,17 @@ def main():
|
||||
config = ConfigSchema(**read_json("config/config.json"))
|
||||
monitor = DirectoryMonitor(config.trace_storage_path, config.monitor_update_period)
|
||||
data_converter = DataConverter()
|
||||
mediator = Mediator(monitor, data_converter)
|
||||
plot_widget_builder = plot.PlotWidget()
|
||||
controller = Controller()
|
||||
mediator = Mediator(monitor, data_converter, plot_widget_builder, controller)
|
||||
monitor.start()
|
||||
|
||||
window = MainWindow()
|
||||
|
||||
window.show()
|
||||
|
||||
controller.signal_widgets.connect(window.show_plot_tabs)
|
||||
|
||||
|
||||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user