Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optview rewrite #291

Draft
wants to merge 113 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
412f62b
Removed old opt view files
lamkina Mar 12, 2021
0268ee3
Added skeleton framework for MVC architecture
lamkina Mar 12, 2021
6594c74
Made logo file names more descriptive
lamkina Mar 12, 2021
a1b8565
Created a utils folder for view utilities
lamkina Mar 13, 2021
114c2d3
Initial GUI and controller functionality
lamkina Mar 13, 2021
2a20675
Switched to widgets and nested layouts
lamkina Mar 14, 2021
dd89aad
Renamed plot controller
lamkina Mar 14, 2021
d4e53e1
Renamed plot view
lamkina Mar 14, 2021
86b3ed8
ignore vscode workspace settings
lamkina Mar 14, 2021
6abb656
Added png of pyOptSparse logo to assets
Apr 6, 2021
48b2e2c
Added menu bar, more options, and adjusted sub-layouts
Apr 6, 2021
5a44eb9
Added pyOptSparse watermark to initial plot
Apr 6, 2021
2e0ae5d
Added template for message box views
Apr 7, 2021
2ce791e
Added input handling and changed all widgets to attributes
Apr 7, 2021
64a3602
Added shell functions for input handling
Apr 7, 2021
5484716
Refactor to allow for multiple sub window plotting tabs
Apr 8, 2021
0ab660d
Added toggle switch UI element
Apr 9, 2021
64b2c8e
Added more functionality and state control
Apr 9, 2021
685da0e
Implemented initial data structure and history api methods
Apr 9, 2021
51739a5
Started framework for plotting
Apr 9, 2021
308eae1
Updated plot view to include the pyoptsparse logo
Apr 9, 2021
01fc74e
Encapsulating state control
Apr 9, 2021
18836a0
Added custom switches and state control
Apr 9, 2021
1f15aa1
Added state control and started plotting framework
Apr 14, 2021
99e63ed
Added funcs to scale and unscale x,y vars
Apr 14, 2021
b570729
Re-working plot function to handle new framework
Apr 14, 2021
5ca12a6
Changed image to scale with the window
Apr 14, 2021
62e316e
Added more state control
Apr 14, 2021
43c6538
Removed shared x-axis option
Apr 14, 2021
8186d05
Added file to ignore
Apr 27, 2021
fe94ebd
Refactored to match new model
Jun 3, 2021
072d94b
Adding new data structures to better handle all features
Jun 3, 2021
8106653
New model using underlying data structures
Jun 3, 2021
951d7d5
Removed state controller
Jun 3, 2021
41ecf0e
Updated view to match controller refactor
Jun 3, 2021
3481cc6
Refactored to help encapsulate functionality
Jun 6, 2021
a32002e
Adding custom widgets for plot and variable list objects
Jun 6, 2021
06d4f83
Refactored to represent current sub architecture organization
Jun 6, 2021
62e81df
Refactored sub windows
Jun 6, 2021
045c68b
Fixed add/remove variable logic and added options
Jun 6, 2021
69de609
Added a model to the configure plot MVC
Jun 6, 2021
5845eaf
Added variable list widget and added middle layout
Jun 6, 2021
241eed6
Switched location of plot list widget
Jun 6, 2021
1fe71f1
Added tab widgets
Jun 6, 2021
72fe6a9
Removed the variable index
Jun 6, 2021
6d7ce91
Refactored to clearer locations
Jun 6, 2021
bd8417f
Started implementing options
Jun 7, 2021
e1f7aa0
Adding minor and major iteration logic control
Jun 7, 2021
8c5ee87
Added major and minor iteration toggles
Jun 7, 2021
baaeac1
Unused so I deleted it
Jun 7, 2021
a83367d
Set the MplCanvas parent to a figure not a widget
Jun 7, 2021
b3c9c6b
Added subplot labels
Jun 7, 2021
944148b
Documentation tweak
Jun 7, 2021
0911144
Removed unessecary x variable functionality and updated configure win…
Jun 10, 2021
5cf1d6e
Updated the model to reflect removal of x variables from view
Jun 10, 2021
dc5ebe6
Moved the variable list widget into different location and replaced t…
Jun 10, 2021
0f36798
Widgets file for custom configure window widgets
Jun 10, 2021
06fe2d5
Removed x/y variable supprort in favor of x axis being just major/min…
Jun 10, 2021
4dda2e1
Merge branch 'master' of https://github.com/lamkina/pyoptsparse into …
Jun 10, 2021
820ce8d
Added scaling and bounds control
Jun 12, 2021
a3c5682
Removed specific variable options
Jun 12, 2021
04b4568
Added options to each variable class
Jun 12, 2021
7e63da8
Merge branch 'master' of https://github.com/mdolab/pyoptsparse into o…
lamkina Jan 6, 2022
2158be9
Included add file functionality in the plot configuration
lamkina Jan 7, 2022
6a6f75e
Adjusted the error message for too many plots in a subwindow
lamkina Jan 7, 2022
f7487c4
Removed postprocessing setup code to prevent install errors during de…
lamkina Jan 7, 2022
bb9e5a8
Working on the plot configuration window
Jan 7, 2022
f80053e
Merge branch 'optview_rewrite' of https://github.com/lamkina/pyoptspa…
Jan 7, 2022
3a38071
Fixing bugs with the plot configuration window
Jan 7, 2022
2716b25
Removed print statements
Jan 7, 2022
f72bea5
Major refactor of the configuration window, added the refresh feature…
Mar 30, 2022
e59a85d
Merged with branch 'main' from mdolab/pyoptsparse
Mar 30, 2022
162a823
Started implementing separate x and y variables for plots
Mar 30, 2022
308a34f
Created a new MVC for handling x and y variables with real-time plott…
Mar 31, 2022
97d5cb5
Working on making the new variable plotting framework functional, and…
lamkina Apr 1, 2022
28c7536
Fixed most of the bugs with plotting and formatting. Also added warn…
lamkina Apr 2, 2022
3ce297b
Added command line argument for adding files
lamkina Apr 2, 2022
98aa74b
Fixed plotting bugs and added scaled/bounds options functionality
lamkina Apr 3, 2022
84387eb
Added docstrings, updated import format, and did a minor refactor wit…
lamkina Apr 3, 2022
01797e1
Merge branch 'main' of github.com:mdolab/pyoptsparse into optview_rew…
lamkina Apr 3, 2022
2ada904
Updated flake8 config and added new optview dependencies to setup
lamkina Apr 4, 2022
419b901
Flake8, black, and isort fixes
lamkina Apr 4, 2022
0b26e6a
Flake8 and I are having fun
lamkina Apr 4, 2022
c8dd991
Added optview as a cli tool and fixed bugs with file paths
Apr 4, 2022
b971bfa
Changed the asset path to be absolute based on the install directory
Apr 4, 2022
16c6737
File dialogs now open to the directory from which OptView was launched
Apr 4, 2022
31d6c76
removed unnecessary import
marcomangano Apr 5, 2022
b28c8c1
Data now loads with the file, all DV's get displayed, curve labels ar…
lamkina Apr 8, 2022
745480c
Added QtGui colors to their own file
lamkina Apr 8, 2022
d3e569b
Fixed a bug with setting curve labels when adding variables to plots
lamkina Apr 8, 2022
292b59e
Added file display on main window and fixed a bug with setting bounds…
lamkina Apr 8, 2022
d1826cb
Added dark mode, legend config options, and fixed a bug with minor it…
lamkina May 15, 2022
36c250b
Updated optview dependencies for dark mode
lamkina May 15, 2022
152c813
Updated the branch to match main
lamkina May 15, 2022
5ee0bda
Added plot reordering and several keyboard shortcuts
lamkina May 17, 2022
78f7847
Added settings configuration to the file menu
lamkina May 19, 2022
d1a0d6f
Added the views, model, and controller for OptView settings
lamkina May 19, 2022
0b3f138
Added a function to open the settings sub window
lamkina May 19, 2022
14fd5a4
Abstracted the view property to be a common attribute for all control…
lamkina May 19, 2022
89700d0
Made a custom widget for the dark mode toggle in the settings menu
lamkina May 19, 2022
da2ec18
The view for the controller is now set using decorators from the cont…
lamkina May 19, 2022
4aa2cc8
Adding more keyboard shortcuts and updating package names after struc…
Oct 6, 2022
50391b1
Merging updated main with meson build
Oct 6, 2022
e7bb697
Updated to PyQt6 to work with ARM
Oct 12, 2022
da66ae4
Merge branch 'main' of github.com:mdolab/pyoptsparse into optview_rew…
Oct 12, 2022
ea9eecb
Fixing flake8 errors
Oct 12, 2022
02d5744
Fixing black formatting
Oct 12, 2022
9f1f08f
Fixing isort formatting
Oct 12, 2022
b7f7945
Added updated optview logo that matches mdolab colors
Oct 12, 2022
e03ccba
Fixing meson build file
Oct 12, 2022
748b492
Fixing more meson build issues
Oct 12, 2022
c6dbff0
Major refactor to improve maintainablility
Oct 12, 2022
9500b1e
Fixing meson build issues
Oct 13, 2022
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
Prev Previous commit
Next Next commit
Major refactor to improve maintainablility
Andrew Lamkin committed Oct 12, 2022
commit c6dbff045cd0a14e4084913f112bb7f2dba68262
6 changes: 3 additions & 3 deletions pyoptsparse/postprocessing/OptView.py
Original file line number Diff line number Diff line change
@@ -6,14 +6,14 @@

# External modules
from PyQt6.QtGui import QAction, QIcon, QKeySequence, QShortcut
from PyQt6.QtWidgets import QApplication, QMenuBar, QTabWidget, QVBoxLayout, QWidget
from PyQt6.QtWidgets import QApplication, QMenuBar, QTabWidget, QVBoxLayout

# First party modules
from pyoptsparse.postprocessing.baseclasses.view import View
from pyoptsparse.postprocessing.baseclasses import View
from pyoptsparse.postprocessing.opt_view_controller import OptViewController


class MainView(QWidget, View):
class MainView(View):
def __init__(self, *args, file_names: List = [], **kwargs):
"""
OptView - A GUI designed to assist viewing optimization problems
Binary file not shown.
31 changes: 31 additions & 0 deletions pyoptsparse/postprocessing/baseclasses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# External modules
from PyQt6.QtWidgets import QWidget


class View(QWidget):
def __init__(self, *args, **kwargs) -> None:
super(View, self).__init__(*args, **kwargs)


class Controller(object):
def __init__(self, *args, **kwargs):
"""
Base class for controller objects.
"""
self._view = None

@property
def view(self) -> View:
return self._view

@view.setter
def view(self, view: View):
self._view = view


class Model(object):
def __init__(self, *args, **kwargs) -> None:
"""
Base class for model objects.
"""
pass
Empty file.
18 changes: 0 additions & 18 deletions pyoptsparse/postprocessing/baseclasses/controller.py

This file was deleted.

12 changes: 0 additions & 12 deletions pyoptsparse/postprocessing/baseclasses/meson.build

This file was deleted.

6 changes: 0 additions & 6 deletions pyoptsparse/postprocessing/baseclasses/model.py

This file was deleted.

3 changes: 0 additions & 3 deletions pyoptsparse/postprocessing/baseclasses/view.py

This file was deleted.

7 changes: 7 additions & 0 deletions pyoptsparse/postprocessing/colors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# External modules
from PyQt6.QtGui import QColor

# --- Color constants ---
GREEN = QColor(0, 255, 0, 20)
BLUE = QColor(0, 150, 255, 20)
WHITE = QColor(255, 255, 255)
Original file line number Diff line number Diff line change
@@ -1,7 +1,91 @@
# External modules
from PyQt6.QtCore import QPropertyAnimation, QRectF, QSize, Qt, pyqtProperty
from PyQt6.QtGui import QPainter
from PyQt6.QtWidgets import QAbstractButton, QSizePolicy, QWidget
from PyQt6.QtCore import QPropertyAnimation, QRectF, QSize, QSortFilterProxyModel, Qt, pyqtProperty
from PyQt6.QtGui import QColor, QDropEvent, QKeySequence, QPainter, QShortcut
from PyQt6.QtWidgets import (
QAbstractButton,
QComboBox,
QCompleter,
QHBoxLayout,
QLineEdit,
QListWidget,
QPushButton,
QSizePolicy,
QTableWidgetItem,
QTreeWidgetItem,
QWidget,
)

# First party modules
from pyoptsparse.postprocessing.baseclasses import Controller, View
from pyoptsparse.postprocessing.data_structures import File

# --- Color constants ---
GREEN = QColor(0, 255, 0, 20)
BLUE = QColor(0, 150, 255, 20)
WHITE = QColor(255, 255, 255)


class Button(QPushButton):
def __init__(self, *args, **kwargs):
"""
Inherits the PyQt6 push button class and implements a custom
button format.
"""
super().__init__(*args, **kwargs)
self.resize(150, 30)


class ExtendedComboBox(QComboBox):
def __init__(self, parent: QWidget = None):
"""
Combobox view with custom autocomplete functionality for storing and
searching for variables

Parameters
----------
parent : PyQt6.QtWidgets.QWidget, optional
The parent view, by default None
"""
super(ExtendedComboBox, self).__init__(parent)

self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
self.setEditable(True)

# add a filter model to filter matching items
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())

# add a completer, which uses the filter model
self.completer = QCompleter(self.pFilterModel, self)
# always show all (filtered) completions
self.completer.setCompletionMode(QCompleter.CompletionMode.UnfilteredPopupCompletion)
self.setCompleter(self.completer)

# connect signals
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)

# on selection of an item from the completer, select the
# corresponding item from combobox
def on_completer_activated(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)

# on model change, update the models of the filter and completer
# as well
def setModel(self, model):
super(ExtendedComboBox, self).setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)

# on model column change, update the model column of the filter
# and completer as well
def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super(ExtendedComboBox, self).setModelColumn(column)


class Switch(QAbstractButton):
@@ -215,3 +299,101 @@ def enterEvent(self, event):
"""
self.setCursor(Qt.CursorShape.PointingHandCursor)
super().enterEvent(event)


class PlotList(QListWidget, View):
def __init__(self, parent: QWidget = None, controller: Controller = None) -> None:
super(PlotList, self).__init__(parent)

self.controller = controller

self.plot_up_action = QShortcut(QKeySequence("Ctrl+Up"), self)
self.plot_down_action = QShortcut(QKeySequence("Ctrl+Down"), self)

self.plot_up_action.activated.connect(self.movePlotUp)
self.plot_down_action.activated.connect(self.movePlotDown)

def dropEvent(self, event: QDropEvent) -> None:
super(PlotList, self).dropEvent(event)
self.controller.reorder_plots()

def movePlotUp(self) -> None:
self.controller.move_plot_up()

def movePlotDown(self) -> None:
self.controller.move_plot_down()


class PlotListWidget(View):
def __init__(self, parent: QWidget = None, controller: Controller = None, idx: int = 0):
"""
Custom list widget that adds functionality for configuring and
removing plots. The widget needs access to the tab window
controller so the embedded buttons can call functions for
configuring and removing plots.

Parameters
----------
parent : PyQt6.QtWidgets.QWidget, optional
The parent view, by default None
controller : Controller, optional
Tab controller linked to the tab view., by default None
idx : int, optional
The index of the plot in the tab model, by default 0
"""
super(PlotListWidget, self).__init__(parent)

self.controller = controller
self.idx = idx

# Set the plot title
self.title = QLineEdit(f"Plot {idx}")

# Add the configure plot button
self.configure_button = QPushButton("Configure/Add Variables")
self.configure_button.clicked.connect(self.configure)

# Add the remove plot button
self.remove_button = QPushButton("Remove Plot")
self.remove_button.clicked.connect(self.remove)

# Configure the layout
layout = QHBoxLayout()
layout.addWidget(self.title, 1)
layout.addWidget(self.configure_button, 1)
layout.addWidget(self.remove_button, 1)

# Set the layout
self.setLayout(layout)

def remove(self):
"""
Calls the remove_plot function in the tab controller.
"""
self.controller.remove_plot(self.idx)

def configure(self):
"""
Calls teh configure_view function in the tab controller.
"""
self.controller.configure_view(self.idx)


class FileTreeWidgetItem(QTreeWidgetItem):
def __init__(self, *args, **kwargs):
"""
Custom tree widget item that can store file objects.
"""
self.file = None
super().__init__(*args, **kwargs)

def setFile(self, file: File):
self.file = file


class FileTableWidgetItem(QTableWidgetItem):
def __init__(self, *args, **kwargs):
"""
Custom file table widget item.
"""
super(FileTableWidgetItem, self).__init__(*args, **kwargs)
9 changes: 6 additions & 3 deletions pyoptsparse/postprocessing/meson.build
Original file line number Diff line number Diff line change
@@ -3,6 +3,11 @@ python_sources = [
'__init__.py',
'OptView.py',
'opt_view_controller.py',
'baseclasses.py',
'data_structures.py',
'colors.py',
'general_widgets.py',
'utils.py',
]

py3_target.install_sources(
@@ -23,6 +28,4 @@ py3_target.install_sources(
subdir: 'pyoptsparse/postprocessing/assets'
)

subdir('baseclasses')
subdir('sub_windows')
subdir('utils')
subdir('sub_windows')
12 changes: 6 additions & 6 deletions pyoptsparse/postprocessing/opt_view_controller.py
Original file line number Diff line number Diff line change
@@ -5,11 +5,9 @@
from PyQt6.QtWidgets import QInputDialog, QLineEdit

# First party modules
from pyoptsparse.postprocessing.baseclasses.controller import Controller
from pyoptsparse.postprocessing.sub_windows.settings_window.settings_controller import SettingsController
from pyoptsparse.postprocessing.sub_windows.settings_window.settings_view import SettingsView
from pyoptsparse.postprocessing.sub_windows.tab_window.tab_controller import TabController
from pyoptsparse.postprocessing.sub_windows.tab_window.tab_view import TabView
from pyoptsparse.postprocessing.baseclasses import Controller
from pyoptsparse.postprocessing.sub_windows.settings_window import SettingsController, SettingsView
from pyoptsparse.postprocessing.sub_windows.tab_window import TabController, TabView


class OptViewController(Controller):
@@ -32,7 +30,9 @@ def addTab(self, interactive: bool = True, tab_name: str = "Home", file_names: L
Adds a tab to the main view.
"""
if interactive:
tab_name, ok_pressed = QInputDialog.getText(self.view, "Enter Tab Name", "Tab Name:", QLineEdit.Normal, "")
tab_name, ok_pressed = QInputDialog.getText(
self.view, "Enter Tab Name", "Tab Name:", QLineEdit.EchoMode.Normal, ""
)
tab_controller = TabController(self.view, file_names=file_names)
tab_view = TabView(self.view, tab_controller)
self.view.tabs.addTab(tab_view, tab_name)
Loading