74 lines
3.5 KiB
Python
74 lines
3.5 KiB
Python
from __future__ import annotations
|
|
|
|
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg, NavigationToolbar2QT
|
|
from matplotlib.figure import Figure
|
|
from PySide6.QtCore import Signal
|
|
from PySide6.QtWidgets import QVBoxLayout, QWidget
|
|
|
|
from bedit_gui.simulation_models import SimulationPlotSettings
|
|
from bedit_simulation import SimulationResult
|
|
|
|
|
|
class SimulationPlotWidget(QWidget):
|
|
settings_requested = Signal()
|
|
|
|
def __init__(self, parent: QWidget | None = None) -> None:
|
|
super().__init__(parent)
|
|
self.figure = Figure(layout="constrained")
|
|
self.canvas = FigureCanvasQTAgg(self.figure)
|
|
self.toolbar = NavigationToolbar2QT(self.canvas, self)
|
|
for action in self.toolbar.actions():
|
|
if action.text() in ("Customize", "Subplots"):
|
|
self.toolbar.removeAction(action)
|
|
self.toolbar.addSeparator()
|
|
self.settings_action = self.toolbar.addAction("Plot settings…")
|
|
self.settings_action.setToolTip("Edit plot title, axes, traces, grid, and legend")
|
|
self.settings_action.triggered.connect(self.settings_requested)
|
|
self.axes = self.figure.add_subplot()
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
layout.addWidget(self.toolbar)
|
|
layout.addWidget(self.canvas)
|
|
|
|
def set_plot(self, results: list[SimulationResult], signals: list[str], x_axis: str | None = None, settings: SimulationPlotSettings | None = None) -> None:
|
|
settings = settings or SimulationPlotSettings()
|
|
self.axes.clear()
|
|
for signal in signals:
|
|
trace = settings.traces.get(signal)
|
|
if trace is not None and not trace.visible:
|
|
continue
|
|
x_values: list[float] = []
|
|
values: list[float] = []
|
|
sample_offset = 0
|
|
for result in results:
|
|
result_values = result.data.get(signal)
|
|
if result_values is None:
|
|
continue
|
|
result_x = result.data.get(x_axis or "time")
|
|
if result_x is not None and len(result_x) == len(result_values):
|
|
x_values.extend(result_x)
|
|
elif x_axis is not None:
|
|
continue
|
|
else:
|
|
x_values.extend(range(sample_offset, sample_offset + len(result_values)))
|
|
values.extend(result_values)
|
|
sample_offset += len(result_values)
|
|
if values:
|
|
options = {"label": trace.label or signal, "linestyle": trace.line_style, "linewidth": trace.line_width, "marker": trace.marker or None, "markersize": trace.marker_size} if trace is not None else {"label": signal}
|
|
if trace is not None and trace.color:
|
|
options["color"] = trace.color
|
|
self.axes.plot(x_values, values, **options)
|
|
self.axes.set_title(settings.title)
|
|
self.axes.set_xlabel(settings.x_label or x_axis or "Time")
|
|
self.axes.set_ylabel(settings.y_label)
|
|
self.axes.set_xscale(settings.x_scale)
|
|
self.axes.set_yscale(settings.y_scale)
|
|
if not settings.x_auto:
|
|
self.axes.set_xlim(settings.x_min, settings.x_max)
|
|
if not settings.y_auto:
|
|
self.axes.set_ylim(settings.y_min, settings.y_max)
|
|
self.axes.grid(settings.grid_visible, axis=settings.grid_axis, linestyle=settings.grid_style, alpha=settings.grid_alpha)
|
|
if self.axes.lines and settings.legend_visible:
|
|
self.axes.legend(loc=settings.legend_location)
|
|
self.canvas.draw_idle()
|