Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Flexible amount does not save (issue 69)
- Setable variable to activate the ability to set invisible elements values (issue 72)
- Problem with autosaving (issue 74)
- Inconsistent figure font layout (issue 97)
- Changing aims is not noticed (issue 98)

### Changed
- list_ds in MainWindow removed and replaced by QListWidget data
Expand Down
4 changes: 2 additions & 2 deletions ScenarioGUI/gui_classes/gui_combine_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ def hide_no_result(hide: bool = True):
fig_obj.show()
fig_obj.canvas.show()
# draw new plot
fig.tight_layout()
fig.tight_layout() if fig_obj.frame.isVisible() else None
fig_obj.canvas.draw()
# set figure to datastorage
setattr(ds, fig_name, fig)
Expand All @@ -1539,7 +1539,7 @@ def hide_no_result(hide: bool = True):
fig_obj.show()
fig_obj.canvas.show()
# draw new plot
fig.tight_layout()
fig.tight_layout() if fig_obj.frame.isVisible() and not(fig_obj.fig.get_tight_layout()) else None
fig_obj.canvas.draw()

# update result for every ResultText object
Expand Down
16 changes: 11 additions & 5 deletions ScenarioGUI/gui_classes/gui_structure_classes/font_list_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class FontListBox(ListBox):
The ListBox can be used to select one option out of many (sort of like the ButtonBox)
"""

LinkMatrix: list[int] | None = None

def __init__(self, label: str | list[str], default_index: int, entries: list[str], category: Category):
"""

Expand Down Expand Up @@ -67,13 +69,17 @@ def __init__(self, label: str | list[str], default_index: int, entries: list[str
self.widget: FontComboBox = FontComboBox(self.default_parent)
self.widget.clear()
self.widget.addItems(self.entries)
self._link_matrix: list[int] | None = None

def link_matrix(self) -> list[int]:
return [[self.widget.itemText(index) for index in range(self.widget.count())].index(font) for font in self.entries]

def create_widget(
self,
frame: QtW.QFrame,
layout_parent: QtW.QLayout,
row: int = None,
column: int = None,
row: int | None = None,
column: int | None = None,
) -> None:
"""
This functions creates the ListBox widget in the frame.
Expand All @@ -84,10 +90,10 @@ def create_widget(
The frame object in which the widget should be created
layout_parent : QtW.QLayout
The parent layout of the current widget
row : int
row : int | None
The index of the row in which the widget should be created
(only needed when there is a grid layout)
column : int
column : int | None
The index of the column in which the widget should be created
(only needed when there is a grid layout)

Expand All @@ -103,7 +109,7 @@ def create_widget(
f"QComboBox QAbstractItemView::item:hover{'{'}color: {globs.WHITE};background-color: {globs.LIGHT_SELECT};{'}'}"
f"QComboBox QAbstractItemView::item:selected{'{'}color: {globs.WHITE};background-color: {globs.LIGHT_SELECT};{'}'}"
)
self.widget.setCurrentIndex(self.default_value)
self.widget.setCurrentIndex(self.link_matrix().index(self.default_value))
if self.limit_size:
# self.widget.setMaximumWidth(100)
self.widget.setMinimumWidth(100)
Expand Down
97 changes: 54 additions & 43 deletions ScenarioGUI/gui_classes/gui_structure_classes/result_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@
from __future__ import annotations

import copy
import logging
import os
from typing import TYPE_CHECKING

import matplotlib as mpl
import matplotlib.font_manager as fm
import matplotlib.pyplot as plt
import numpy as np
import PySide6.QtCore as QtC # type: ignore
import PySide6.QtGui as QtG # type: ignore
import PySide6.QtWidgets as QtW # type: ignore
from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.colors import to_rgb
Expand Down Expand Up @@ -52,14 +48,14 @@ def get_name(font: fm.FontProperties) -> str:


font_list: list[fm.FontProperties] = [fm.FontProperties(fname=font_path, size=12) for font_path in fm.findSystemFonts()]
font_list = sorted(font_list, key=lambda x: get_name(x))
font_list = sorted(font_list, key=lambda x: x.get_file().upper().split("\\")[-1].replace(".TTF", ""))
font_name_set = set()
font_list = [font for font in font_list if get_name(font) not in font_name_set and not font_name_set.add(get_name(font))]
font_list_by_name: list[str] = [get_name(font).upper() for font in font_list]


# overwrite navigationToolbar
class NavigationToolbarScenarioGUI(NavigationToolbar):

def __init__(self, overwrite: bool, canvas, parent, coordinate):
self.overwrite = overwrite
super().__init__(canvas, parent, coordinate)
Expand All @@ -70,7 +66,7 @@ def save_figure(self, *args):
old_figure = self.canvas.figure
self.canvas.figure = copy.deepcopy(self.canvas.figure)
globs.set_print_layout(self.canvas.figure.get_axes()[0])
self.canvas.figure.set_facecolor('white')
self.canvas.figure.set_facecolor("white")
res = super().save_figure(args)
self.canvas.figure = old_figure
return res
Expand All @@ -83,9 +79,15 @@ class ResultFigure(Category):
It is a category showing a figure and optionally a couple of FigureOptions to alter this figure.
"""

def __init__(self, label: str | list[str], page: Page, x_axes_text: str | None = None,
y_axes_text: str | None = None, customizable_figure: int = 0,
legend_text: str | None = None):
def __init__( # noqa: PLR0913, PLR0915
self,
label: str | list[str],
page: Page,
x_axes_text: str | None = None,
y_axes_text: str | None = None,
customizable_figure: int = 0,
legend_text: str | None = None,
):
"""

Parameters
Expand Down Expand Up @@ -126,7 +128,9 @@ def __init__(self, label: str | list[str], page: Page, x_axes_text: str | None =
self.canvas: FigureCanvas = FigureCanvas(self.fig)
self.canvas.a_x = self.a_x
# create navigation toolbar and replace icons with white ones
self.toolbar: NavigationToolbarScenarioGUI = NavigationToolbarScenarioGUI(overwrite=customizable_figure==1, canvas=self.canvas, parent=None, coordinate=True)
self.toolbar: NavigationToolbarScenarioGUI = NavigationToolbarScenarioGUI(
overwrite=customizable_figure == 1, canvas=self.canvas, parent=None, coordinate=True
)
for name, icon_name in [
("save_figure", "Save_Inv"),
("home", "Home"),
Expand Down Expand Up @@ -215,7 +219,7 @@ def __init__(self, label: str | list[str], page: Page, x_axes_text: str | None =
label="Font family: ",
category=self,
entries=[get_name(font) for font in font_list],
default_index=[get_name(font).upper() for font in font_list].index(globs.FONT.upper()),
default_index=font_list_by_name.index(globs.FONT.upper()),
)
self.option_save_layout = FunctionButton(button_text="Save layout", category=self, icon="Save")
self.default_figure_colors.add_link_2_show(self.option_figure_background, on_index=0)
Expand All @@ -239,14 +243,16 @@ def __init__(self, label: str | list[str], page: Page, x_axes_text: str | None =
self.update_default_settings()

def update_default_settings(self):
self.default_settings = {"figure_background": self.option_figure_background.get_value(),
"plot_background": self.option_plot_background.get_value(),
"axes_text": self.option_axes_text.get_value(),
"axes": self.option_axes.get_value(),
"title": self.option_title.get_value(),
"legend_text": self.option_legend_text.get_value(),
"font_size": self.option_font_size.get_value(),
"font": self.option_font.get_value()}
self.default_settings = {
"figure_background": self.option_figure_background.get_value(),
"plot_background": self.option_plot_background.get_value(),
"axes_text": self.option_axes_text.get_value(),
"axes": self.option_axes.get_value(),
"title": self.option_title.get_value(),
"legend_text": self.option_legend_text.get_value(),
"font_size": self.option_font_size.get_value(),
"font": self.option_font.link_matrix()[self.option_font.get_value()[0]],
}

def change_2_default_settings(self):
if self.default_figure_colors.get_value() == 1:
Expand All @@ -256,9 +262,9 @@ def change_2_default_settings(self):
self.a_x.tick_params(axis="y", colors=to_rgb(np.array(self.default_settings["axes"]) / 255))
self._change_axes_color(self.default_settings["axes_text"])
self._change_legend_text_color(self.default_settings["legend_text"])
self._change_font(self.default_settings["font"][0], self.default_settings["font_size"])
self.fig.tight_layout()
self.canvas.draw()
self._change_font(self.default_settings["font"], self.default_settings["font_size"])
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None
return
self.change_figure_background_color()
self.change_plot_background_color()
Expand All @@ -269,8 +275,10 @@ def change_2_default_settings(self):
self.change_font()

def update_figure_layout(self, event):
self.canvas.draw() # Redraw the canvas
self.fig.tight_layout() # Adjust the layout of the figure
self.canvas.draw() if self.frame.isVisible() else None # Redraw the canvas
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None # Adjust the layout of the figure
self.frame_canvas.setMinimumHeight(self.frame_canvas.window().size().height() * 0.6)
self.frame_canvas.setMaximumHeight(self.frame_canvas.window().size().height() * 0.6)
QtW.QFrame.resizeEvent(self.frame_canvas, event)

def replace_figure(self, fig: plt.Figure) -> None:
Expand Down Expand Up @@ -301,7 +309,9 @@ def replace_figure(self, fig: plt.Figure) -> None:
self.toolbar.hide()
canvas = FigureCanvas(self.fig)
# create navigation toolbar and replace icons with white ones
toolbar: NavigationToolbarScenarioGUI = NavigationToolbarScenarioGUI(overwrite=self.customizable_figure==1, canvas=canvas, parent=self.frame_canvas, coordinate=True)
toolbar: NavigationToolbarScenarioGUI = NavigationToolbarScenarioGUI(
overwrite=self.customizable_figure == 1, canvas=canvas, parent=self.frame_canvas, coordinate=True
)
for name, icon_name in [
("save_figure", "Save_Inv"),
("home", "Home"),
Expand Down Expand Up @@ -331,7 +341,7 @@ def replace_figure(self, fig: plt.Figure) -> None:
if self.customizable_figure == 2:
self.change_2_default_settings()
else:
self._change_font([get_name(font).upper() for font in font_list].index(globs.FONT.upper()), globs.FONT_SIZE)
self._change_font(font_list_by_name.index(globs.FONT.upper()), globs.FONT_SIZE)

def create_widget(self, page: QtW.QScrollArea, layout: QtW.QLayout):
"""
Expand Down Expand Up @@ -363,6 +373,7 @@ def create_widget(self, page: QtW.QScrollArea, layout: QtW.QLayout):
self.layout_frame.addWidget(self.frame_canvas)
# set minimal height to ensure a minimal height of the plots
self.frame_canvas.setMinimumHeight(500)
self.frame_canvas.setMaximumHeight(500)
# add canvas and toolbar to local frame
self.layout_frame_canvas.addWidget(self.canvas)
self.layout_frame_canvas.addWidget(self.toolbar)
Expand All @@ -387,18 +398,18 @@ def create_widget(self, page: QtW.QScrollArea, layout: QtW.QLayout):

def change_figure_background_color(self):
self.fig.set_facecolor(to_rgb(np.array(self.option_figure_background.get_value()) / 255))
self.fig.tight_layout()
self.canvas.draw()
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def change_plot_background_color(self):
self.a_x.set_facecolor(to_rgb(np.array(self.option_plot_background.get_value()) / 255))
self.fig.tight_layout()
self.canvas.draw()
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def change_axes_color(self):
self._change_axes_color(self.option_axes.get_value())
self.fig.tight_layout()
self.canvas.draw()
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def _change_axes_color(self, color: tuple[int, int, int]):
self.a_x.tick_params(axis="x", colors=to_rgb(np.array(color) / 255))
Expand All @@ -410,19 +421,19 @@ def _change_axes_color(self, color: tuple[int, int, int]):

def change_title_color(self):
self.a_x.set_title(self.a_x.get_title(), color=to_rgb(np.array(self.option_title.get_value()) / 255))
self.fig.tight_layout()
self.canvas.draw()
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def change_axis_text_color(self):
self.a_x.xaxis.label.set_color(to_rgb(np.array(self.option_axes_text.get_value()) / 255))
self.a_x.yaxis.label.set_color(to_rgb(np.array(self.option_axes_text.get_value()) / 255))
self.fig.tight_layout()
self.canvas.draw()
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def change_legend_text_color(self):
self._change_legend_text_color(self.option_legend_text.get_value())
self.fig.tight_layout()
self.canvas.draw()
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def _change_legend_text_color(self, colors: tuple[int, int, int]):
legend = self.a_x.get_legend()
Expand All @@ -432,9 +443,9 @@ def _change_legend_text_color(self, colors: tuple[int, int, int]):
text.set_color(to_rgb(np.array(colors) / 255))

def change_font(self):
self._change_font(self.option_font.get_value()[0], self.option_font_size.get_value())
self.fig.tight_layout()
self.canvas.draw()
self._change_font(self.option_font.link_matrix()[self.option_font.get_value()[0]], self.option_font_size.get_value())
self.fig.tight_layout() if self.frame.isVisible() and not(self.fig.get_tight_layout()) else None
self.canvas.draw() if self.frame.isVisible() else None

def _change_font(self, font_index: int, font_size: int):
font: fm.FontProperties = font_list[font_index]
Expand All @@ -447,7 +458,7 @@ def _change_font(self, font_index: int, font_size: int):
_ = [label.set_fontproperties(font) for label in self.a_x.get_xticklabels()]
_ = [label.set_fontproperties(font) for label in self.a_x.get_yticklabels()]
if self.a_x.get_title() is not None:
self.a_x.set_title(self.a_x.get_title(), fontproperties=font)
self.a_x.set_title(self.a_x.get_title(), fontproperties=font, fontstyle="italic", fontweight="bold")
legend = self.a_x.get_legend()
if legend is not None:
for text in legend.get_texts():
Expand Down
27 changes: 27 additions & 0 deletions examples/start_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,38 @@ def __init__(self, default_parent: QtW.QWidget, translations: Translations):
)
self.figure_results_multiple_lines.fig_to_be_shown(class_name="ResultsClass", function_name="create_plot_multiple_lines")

self.figure_results_with_different_other_saved_figure = els.ResultFigure(label=self.translations.figure_results,
page=self.page_result, x_axes_text="X-Axes", y_axes_text="Y-Axes",
customizable_figure=1)
self.legend_figure_results_with_other_saved_figure = els.FigureOption(
category=self.figure_results_with_different_other_saved_figure, label="Legend on", param="legend", default=0, entries=["No", "Yes"],
entries_values=[False, True]
)

self.figure_results_with_different_other_saved_figure.fig_to_be_shown(class_name="ResultsClass", function_name="create_plot")

self.figure_results_with_customizable_layout = els.ResultFigure(label=self.translations.figure_results, page=self.page_result,
x_axes_text="X-Axes", y_axes_text="Y-Axes", customizable_figure=2)
self.legend_figure_results_with_customizable_layout = els.FigureOption(
category=self.figure_results_with_customizable_layout, label="Legend on", param="legend", default=0, entries=["No", "Yes"],
entries_values=[False, True]
)

self.figure_results_with_customizable_layout.fig_to_be_shown(class_name="ResultsClass", function_name="create_plot")

self.aim_add.add_link_2_show(self.result_text_add)
self.aim_add.add_link_2_show(self.result_export)
self.aim_sub.add_link_2_show(self.result_text_sub)
self.aim_plot.add_link_2_show(self.figure_results)

self.aim_add.add_link_2_show(self.figure_results_with_different_other_saved_figure)
self.aim_sub.add_link_2_show(self.figure_results_with_different_other_saved_figure)
self.aim_plot.add_link_2_show(self.figure_results_with_different_other_saved_figure)

self.aim_add.add_link_2_show(self.figure_results_with_customizable_layout)
self.aim_sub.add_link_2_show(self.figure_results_with_customizable_layout)
self.aim_plot.add_link_2_show(self.figure_results_with_customizable_layout)

self.create_settings_page()
self.create_lists()
# you can either automatically links all pages by order of creation
Expand Down
2 changes: 1 addition & 1 deletion tests/gui_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ ICON_NAME: icon.svg
PATH_2_ICONS: ././ScenarioGUI/
FONT_WINDOWS: Arial
FONT_MAC: Helvetica
FONT_SIZE_WINDOWS: 10
FONT_SIZE_WINDOWS: 11
FONT_SIZE_MAC: 14
2 changes: 0 additions & 2 deletions tests/gui_structure_for_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,6 @@ def __init__(self, default_parent: QtW.QWidget, translations: Translations):

self.figure_results_with_customizable_layout.fig_to_be_shown(class_name="ResultsClass", function_name="create_plot")

self.figure_results.fig_to_be_shown(class_name="ResultsClass", function_name="create_plot")

self.aim_add.add_link_2_show(self.result_text_add)
self.aim_sub.add_link_2_show(self.result_text_sub)
self.aim_plot.add_link_2_show(self.figure_results)
Expand Down
4 changes: 4 additions & 0 deletions tests/test_gui_structure_elements/test_aim.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ def test_aim(qtbot):

assert main_window.gui_structure.aim_sub.widget.isChecked()

main_window.save_scenario()
main_window.gui_structure.aim_sub.widget.click()
assert main_window.list_widget_scenario.currentItem().text()[-1] == "*"

main_window.gui_structure.aim_plot.set_text("Hello")
assert main_window.gui_structure.aim_plot.widget.text() == "Hello"
Loading