# -*- coding: utf-8 -*-
'''
Based on previous works by Andrei Udrea 2014 and Volkmar Zabel 2015
Modified and Extended by Simon Marwitz 2015
'''
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.DEBUG)
from .HelpersGUI import DelayedDoubleSpinBox, MyMplCanvas, my_excepthook
from .PlotMSHGUI import ModeShapeGUI
from pyOMA.core.StabilDiagram import StabilPlot, StabilCluster
from pyOMA.core.PlotMSH import ModeShapePlot
from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot, QObject, qInstallMessageHandler, QTimer, QEventLoop
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QPushButton, \
QCheckBox, QButtonGroup, QLabel, QComboBox, \
QTextEdit, QGridLayout, QFrame, QVBoxLayout, QAction, \
QFileDialog, QMessageBox, QApplication, QRadioButton, \
QLineEdit, QSizePolicy, QDoubleSpinBox
import numpy as np
import sys
import os
# check if python is running in headless mode i.e. as a server script
# if 'DISPLAY' in os.environ:
# matplotlib.use("Qt5Agg", force=True)
from matplotlib import rcParams
from matplotlib import ticker
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backend_bases import FigureCanvasBase
from matplotlib.figure import Figure
import matplotlib.pyplot as plot
plot.rc('figure', figsize=[8.5039399474194, 5.255723925793184], dpi=100,)
plot.rc('font', size=10)
plot.rc('legend', fontsize=10, labelspacing=0.1)
plot.rc('axes', linewidth=0.2)
plot.rc('xtick.major', width=0.2)
plot.rc('ytick.major', width=0.2)
plot.ioff()
NoneType = type(None)
sys.excepthook = my_excepthook
[docs]
def resizeEvent_(self, event):
w = event.size().width()
h = event.size().height()
dpival = self.figure.dpi
winch, hinch = self.figure.get_size_inches()
aspect = winch / hinch
if w / h <= aspect:
h = w / aspect
else:
w = h * aspect
winch = w / dpival
hinch = h / dpival
self.figure.set_size_inches(winch, hinch)
FigureCanvasBase.resize_event(self)
self.draw()
self.update()
QWidget.resizeEvent(self, event)
'''
..TODO::
* scale markers right on every platform
* frequency range as argument or from ssi params, sampling freq
* add switch to choose between "unstable only in ..." or "stable in ..."
* (select and merge several poles with a rectangular mouse selection)
* distinguish beetween stabilization criteria and filtering criteria
* add zoom and sliders (horizontal/vertical) for the main figure
* distinguish between "export results" and "save state"
'''
[docs]
class StabilGUI(QMainWindow):
[docs]
def __init__(self, stabil_plot, cmpl_plot, msh_plot=None):
QMainWindow.__init__(self)
self.setWindowTitle(
'Stabilization Diagram: {} - {}'.format(
stabil_plot.stabil_calc.setup_name,
stabil_plot.stabil_calc.start_time))
self.stabil_plot = stabil_plot
self.stabil_calc = stabil_plot.stabil_calc
if self.stabil_calc.state < 2:
self.stabil_calc.calculate_stabilization_masks()
self.create_menu()
self.create_main_frame(cmpl_plot, msh_plot)
self.histo_plot_f = None
self.histo_plot_sf = None
self.histo_plot_d = None
self.histo_plot_sd = None
self.histo_plot_dr = None
self.histo_plot_mac = None
self.histo_plot_mpc = None
self.histo_plot_mpd = None
for index, mode in enumerate(self.stabil_calc.select_modes):
self.mode_selector_add(mode, index)
# self.setGeometry(0, 0, 1800, 1000)
self.show()
for widg in [self.mode_val_view, self.current_value_view]:
widg.setText('\n \n \n \n \n \n \n')
height = widg.document().size().toSize().height() + 3
widg.setFixedHeight(height)
# self.plot_selector_msh.setChecked(True)
self.update_stabil_view()
[docs]
def create_main_frame(self, cmpl_plot, msh_plot):
'''
set up all the widgets and other elements to draw the GUI
'''
main_frame = QWidget()
df_max = self.stabil_calc.df_max * 100
dd_max = self.stabil_calc.dd_max * 100
dmac_max = self.stabil_calc.dmac_max * 100
d_range = self.stabil_calc.d_range
mpc_min = self.stabil_calc.mpc_min
mpd_max = self.stabil_calc.mpd_max
self.fig = self.stabil_plot.fig
self.canvas = FigureCanvasQTAgg(self.fig)
self.canvas.setParent(main_frame)
self.init_cursor()
main_layout = QHBoxLayout()
left_pane_layout = QVBoxLayout()
left_pane_layout.addStretch(1)
palette = QPalette()
palette.setColor(QPalette.Base, Qt.transparent)
self.current_value_view = QTextEdit()
self.current_value_view.setFrameShape(QFrame.Box)
self.current_value_view.setPalette(palette)
self.diag_val_widget = QWidget()
fra_1 = QFrame()
fra_1.setFrameShape(QFrame.Panel)
fra_1.setLayout(
self.create_stab_val_widget(
df_max=df_max,
dd_max=dd_max,
d_mac=dmac_max,
d_range=d_range,
mpc_min=mpc_min,
mpd_max=mpd_max))
left_pane_layout.addWidget(fra_1)
left_pane_layout.addStretch(2)
fra_2 = QFrame()
fra_2.setFrameShape(QFrame.Panel)
fra_2.setLayout(self.create_diag_val_widget())
left_pane_layout.addWidget(fra_2)
left_pane_layout.addStretch(2)
# left_pane_layout.addWidget(self.current_value_view)
# left_pane_layout.addStretch(1)
# right_pane_layout = QVBoxLayout()
self.plot_selector_c = QCheckBox('Mode Shape in Complex Plane')
self.plot_selector_c.toggled.connect(self.toggle_cpl_plot)
self.plot_selector_msh = QCheckBox('Mode Shape in Spatial Model')
self.plot_selector_msh.toggled.connect(self.toggle_msh_plot)
# self.group = QButtonGroup()
# self.group.addButton(self.plot_selector_c)
# self.group.addButton(self.plot_selector_msh)
self.mode_selector = QComboBox()
self.mode_selector.currentIndexChanged[
int].connect(self.update_mode_val_view)
self.mode_plot_widget = QWidget()
self.cmplx_plot_widget = QWidget()
self.cmpl_plot = cmpl_plot
# fig = self.cmpl_plot.fig
# canvas1 = FigureCanvasQTAgg(fig)
# canvas1.setParent(self.cmplx_plot_widget)
self.msh_plot = msh_plot
lay = QHBoxLayout()
# lay.addWidget(canvas1)
self.cmplx_plot_widget.setLayout(lay)
self.cmpl_plot.plot_diagram()
lay = QHBoxLayout()
# lay.addWidget(canvas2)
self.mode_plot_widget.setLayout(lay)
self.mode_val_view = QTextEdit()
self.mode_val_view.setFrameShape(QFrame.Box)
self.mode_val_view.setPalette(palette)
left_pane_layout.addStretch(1)
left_pane_layout.addWidget(self.mode_selector)
left_pane_layout.addWidget(self.plot_selector_c)
left_pane_layout.addWidget(self.plot_selector_msh)
left_pane_layout.addStretch(2)
self.mode_plot_layout = QVBoxLayout()
self.mode_plot_layout.addWidget(self.cmplx_plot_widget)
left_pane_layout.addLayout(self.mode_plot_layout)
left_pane_layout.addStretch(2)
left_pane_layout.addWidget(self.mode_val_view)
left_pane_layout.addStretch(1)
main_layout.addLayout(left_pane_layout)
main_layout.addWidget(self.canvas)
main_layout.setStretchFactor(self.canvas, 1)
# main_layout.addLayout(right_pane_layout)
vbox = QVBoxLayout()
vbox.addLayout(main_layout)
vbox.addLayout(self.create_buttons())
main_frame.setLayout(vbox)
self.stabil_plot.fig.set_facecolor('none')
self.setCentralWidget(main_frame)
self.current_mode = (0, 0)
self.stabil_calc.add_callback('add_mode', self.mode_selector_add)
self.stabil_calc.add_callback('remove_mode', self.mode_selector_take)
return
def create_buttons(self):
b0 = QPushButton('Apply')
b0.released.connect(self.update_stabil_view)
b1 = QPushButton('Save Figure')
b1.released.connect(self.save_figure)
b2 = QPushButton('Export Results')
b2.released.connect(self.save_results)
b3 = QPushButton('Save State')
b3.released.connect(self.save_state)
b4 = QPushButton('OK and Close')
b4.released.connect(self.close)
lay = QHBoxLayout()
lay.addWidget(b0)
lay.addWidget(b1)
lay.addWidget(b2)
lay.addWidget(b3)
lay.addWidget(b4)
lay.addStretch()
return lay
[docs]
def create_histo_plot_f(self):
'''
create
show/hide
update stable
'''
# print('here')
array = self.stabil_calc.freq_diffs
self.histo_plot_f = self.create_histo_plot(
array,
self.histo_plot_f,
title='Frequency Differences (percent)',
ranges=(
0,
1),
select_ranges=[
float(
self.df_edit.text()) /
100],
select_callback=[
lambda x: [
self.df_edit.setText(
str(
x *
100)),
self.update_stabil_view()]])
[docs]
def create_histo_plot_sf(self):
'''
create
show/hide
update stable
'''
array = np.ma.array(
self.stabil_calc.modal_data.std_frequencies /
self.stabil_calc.modal_data.modal_frequencies)
self.histo_plot_sf = self.create_histo_plot(
array,
self.histo_plot_sf,
title='CoV Frequencies (percent)',
ranges=(
0,
1),
select_ranges=[
float(
self.stdf_edit.text()) /
100],
select_callback=[
lambda x: [
self.stdf_edit.setText(
str(
x *
100)),
self.update_stabil_view()]])
[docs]
def create_histo_plot_d(self):
'''
create
show/hide
update stable
'''
array = self.stabil_calc.damp_diffs
self.histo_plot_d = self.create_histo_plot(
array,
self.histo_plot_d,
title='Damping Differences (percent)',
ranges=(
0,
1),
select_ranges=[
float(
self.dd_edit.text()) /
100],
select_callback=[
lambda x: [
self.dd_edit.setText(
str(
x *
100)),
self.update_stabil_view()]])
[docs]
def create_histo_plot_sd(self):
'''
create
show/hide
update stable
'''
array = np.ma.array(
self.stabil_calc.modal_data.std_damping /
self.stabil_calc.modal_data.modal_damping)
self.histo_plot_sd = self.create_histo_plot(
array,
self.histo_plot_sd,
title='CoV Damping (percent)',
ranges=(
0,
1),
select_ranges=[
float(
self.stdd_edit.text()) /
100],
select_callback=[
lambda x: [
self.stdd_edit.setText(
str(
x *
100)),
self.update_stabil_view()]])
[docs]
def create_histo_plot_dr(self):
'''
create
show/hide
update stable
'''
array = np.ma.array(self.stabil_calc.modal_data.modal_damping)
self.histo_plot_dr = self.create_histo_plot(
array, self.histo_plot_dr, title='Damping range ', ranges=(
0, 10), select_ranges=[
float(
self.d_min_edit.text()), float(
self.d_max_edit.text())], select_callback=[
lambda x: [
self.d_min_edit.setText(
str(x)), self.update_stabil_view()], lambda x: [
self.d_max_edit.setText(
str(x)), self.update_stabil_view()]])
[docs]
def create_histo_plot_mac(self):
'''
create
show/hide
update stable
'''
array = self.stabil_calc.MAC_diffs
self.histo_plot_mac = self.create_histo_plot(
array,
self.histo_plot_mac,
title='MAC Diffs (percent)',
ranges=(
0,
1),
select_ranges=[
float(
self.mac_edit.text()) /
100],
select_callback=[
lambda x: [
self.mac_edit.setText(
str(
x *
100)),
self.update_stabil_view()]])
[docs]
def create_histo_plot_mpc(self):
'''
create
show/hide
update stable
'''
array = self.stabil_calc.MPC_matrix
self.histo_plot_mpc = self.create_histo_plot(
array, self.histo_plot_mpc, title='MPC', ranges=(
0, 1), select_ranges=[
float(
self.mpc_edit.text()), None], select_callback=[
lambda x: [
self.mpc_edit.setText(
str(x)), self.update_stabil_view()], str])
[docs]
def create_histo_plot_mpd(self):
'''
create
show/hide
update stable
'''
array = self.stabil_calc.MPD_matrix
self.histo_plot_mpd = self.create_histo_plot(
array, self.histo_plot_mpd, title='MPD', ranges=(
0, 90), select_ranges=[
float(
self.mpd_edit.text())], select_callback=[
lambda x: [
self.mpd_edit.setText(
str(x)), self.update_stabil_view()]])
def show_MC_plot(self):
b = self.sender().isChecked()
self.stabil_plot.show_MC(b)
[docs]
def create_histo_plot(
self,
array,
plot_obj,
title='',
ranges=None,
select_ranges=[None],
select_callback=[None]):
'''
should work like following::
button press if None → visible = True, create
if visible → visible = False, hide
if not visible → visible = True, show
update stabil if None → skip
if visible → visible = visible, update
if not visible → visible = visible, update
close button → visible = False, hide
but doesn't, since the function can not distinguish between
"button press" and "update stabil"
'''
old_mask = np.copy(array.mask)
array.mask = np.ma.nomask
mask_stable = self.stabil_calc.get_stabilization_mask('mask_stable')
if len(array.shape) == 3:
mask = array == 0
array.mask = mask
a = np.min(array, axis=2)
a.mask = mask_stable
stable_data = a.compressed()
else:
array.mask = mask_stable
stable_data = array.compressed()
if plot_obj is None: # create
# print('here again')
mask_pre = self.stabil_calc.get_stabilization_mask('mask_pre')
if len(array.shape) == 3:
mask = array == 0
array.mask = mask
a = np.min(array, axis=2)
a.mask = mask_pre
all_data = a.compressed()
else:
array.mask = mask_pre
all_data = array.compressed()
plot_obj = HistoPlot(
all_data,
stable_data,
title,
ranges,
select_ranges=select_ranges,
select_callback=select_callback)
else: # update
plot_obj.update_histo(stable_data, select_ranges)
array.mask = old_mask
# show (hide is accomplished by just closing the window closeEvent was overridden to self.hide() )
# print('show')
if plot_obj.visible:
plot_obj.show()
return plot_obj
def update_mode_val_view(self, index):
# display information about currently selected mode
i = self.stabil_calc.select_modes[index]
n, f, stdf, d, stdd, mpc, mp, mpd, dmp, dmpd, mtn, MC, ex_1, ex_2 = self.stabil_calc.get_modal_values(
i)
if self.stabil_calc.capabilities['std']:
import scipy.stats
num_blocks = self.stabil_calc.modal_data.num_blocks
stdf = scipy.stats.t.ppf(
0.975, num_blocks) * stdf / np.sqrt(num_blocks)
stdd = scipy.stats.t.ppf(
0.975, num_blocks) * stdd / np.sqrt(num_blocks)
self.current_mode = i
s = ''
for text, val in [('Frequency=%1.3fHz, \n' % (f), f),
('CI Frequency ± %1.3e, \n' % (stdf), stdf),
('Order=%1.0f, \n' % (n), n),
('Damping=%1.3f%%, \n' % (d), d),
('CI Damping ± %1.3e, \n' % (stdd), stdd),
('MPC=%1.5f, \n' % (mpc), mpc),
('MP=%1.3f\u00b0, \n' % (mp), mp),
('MPD=%1.5f\u00b0, \n' % (mpd), mpd),
('dMP=%1.3f\u00b0, \n' % (dmp), dmp),
# ('dMPD=%1.5f\u00b0, \n' % (dmpd), dmpd),
('MTN=%1.5f, \n' % (mtn), mtn),
('MC=%1.5f, \n' % (MC), MC),
('Ext=%1.5f\u00b0, \n' % (ex_1), ex_1),
('Ext=%1.3f\u00b0, \n' % (ex_2), ex_2)
]:
if val is not np.nan:
s += text
self.mode_val_view.setText(s)
height = self.mode_val_view.document().size().toSize().height() + 3
self.mode_val_view.setFixedHeight(height)
self.update_mode_plot(i, mp)
@pyqtSlot(tuple)
def mode_selector_add(self, i, index):
# add mode tomode_selector and select it
n, f, stdf, d, stdd, mpc, mp, mpd, dmp, dmpd, mtn, MC, ex_1, ex_2 = self.stabil_calc.get_modal_values(
i)
# index = self.stabil_calc.select_modes.index(i)
# print(n,f,d,mpc, mp, mpd)
# print(index)
text = '{} - {:2.3f}'.format(index, f)
self.mode_selector.currentIndexChanged[int].disconnect(self.update_mode_val_view)
self.mode_selector.addItem(text)
self.mode_selector.setCurrentIndex(index)
self.update_mode_val_view(index)
self.mode_selector.currentIndexChanged[
int].connect(self.update_mode_val_view)
@pyqtSlot(tuple)
def mode_selector_take(self, i_, index):
if self.current_mode == i_:
if self.stabil_calc.select_modes:
self.current_mode = self.stabil_calc.select_modes[0]
else:
self.current_mode = (0, 0)
self.mode_selector.currentIndexChanged[
int].disconnect(self.update_mode_val_view)
self.mode_selector.clear()
for index, i in enumerate(self.stabil_calc.select_modes):
n, f, stdf, d, stdd, mpc, mp, mpd, dmp, dmpd, mtn, MC, ex_1, ex_2 = self.stabil_calc.get_modal_values(
i)
text = '{} - {:2.3f}'.format(index, f)
self.mode_selector.addItem(text)
if self.current_mode == i:
for ind in range(self.mode_selector.count()):
if text == self.mode_selector.itemText(ind):
break
else:
ind = 0
if self.mode_selector.count():
self.mode_selector.setCurrentIndex(ind)
self.update_mode_val_view(ind)
self.mode_selector.currentIndexChanged[
int].connect(self.update_mode_val_view)
def update_mode_plot(self, i, mpd=None):
# update the plot of the currently selected mode
msh = self.stabil_calc.get_mode_shape(i)
self.cmpl_plot.scatter_this(msh, mpd)
# time.sleep(1)
if self.msh_plot is not None:
self.msh_plot.plot_this(i)
def toggle_msh_plot(self, b):
# change the type of mode plot
# print('msh',b)
if b:
self.msh_plot.show()
else:
self.msh_plot.hide()
def toggle_cpl_plot(self, b):
# change the type of mode plot
# print('cpl',b)
if b:
self.cmpl_plot.show()
else:
self.cmpl_plot.hide()
def init_cursor(self):
self.cursor = self.stabil_plot.init_cursor()
# print(self.stabil_calc.select_modes, type(self.stabil_calc.select_modes))
# self.cursor = DataCursor(
# ax=stabil_plot.ax,
# order_data=stabil_plot.stabil_calc.order_dummy,
# f_data=stabil_plot.stabil_calc.masked_frequencies,
# datalist=stabil_plot.stabil_calc.select_modes,
# color='black', useblit=False)
#
#
# stabil_plot.fig.canvas.mpl_connect(
# 'button_press_event', self.cursor.onmove)
# stabil_plot.fig.canvas.mpl_connect(
# 'resize_event', self.cursor.fig_resized)
# self.cursor.add_datapoints(self.stabil_calc.select_modes)
# self.stabil_calc.select_callback = self.cursor.add_datapoint
self.cursor.add_callback('show_current_info', self.update_value_view)
# self.cursor.show_current_info.connect(
# self.update_value_view)
# self.cursor.add_callback('mode_selected', self.mode_selector_add)
# self.cursor.mode_selected.connect(self.mode_selector_add)
# self.cursor.add_callback('mode_deselected', self.mode_selector_take)
# self.cursor.mode_deselected.connect(self.mode_selector_take)
# @pyqtSlot(bool)
def snap_frequency(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_df')
self.cursor.set_mask(mask, 'mask_df')
# @pyqtSlot(bool)
def snap_damping(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_dd')
self.cursor.set_mask(mask, 'mask_dd')
# @pyqtSlot(bool)
def snap_vector(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_dmac')
self.cursor.set_mask(mask, 'mask_dmac')
# @pyqtSlot(bool)
def snap_stable(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_stable')
self.cursor.set_mask(mask, 'mask_stable')
# @pyqtSlot(bool)
def snap_all(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_pre')
self.cursor.set_mask(mask, 'mask_pre')
# @pyqtSlot(bool)
def snap_clear(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_autoclear')
self.cursor.set_mask(mask, 'mask_autoclear')
# @pyqtSlot(bool)
def snap_select(self, b=True):
if b:
mask = self.stabil_calc.get_stabilization_mask('mask_autoselect')
self.cursor.set_mask(mask, 'mask_autoselect')
def update_value_view(self, i):
n, f, stdf, d, stdd, mpc, mp, mpd, dmp, dmpd, mtn, MC, ex_1, ex_2 = self.stabil_calc.get_modal_values(
i)
if self.stabil_calc.capabilities['std']:
import scipy.stats
num_blocks = self.stabil_calc.modal_data.num_blocks
stdf = scipy.stats.t.ppf(
0.975, num_blocks) * stdf / np.sqrt(num_blocks)
stdd = scipy.stats.t.ppf(
0.975, num_blocks) * stdd / np.sqrt(num_blocks)
self.current_mode = i
s = ''
for text, val in [('Frequency=%1.3fHz, \n' % (f), f),
('CI Frequency ± %1.3e, \n' % (stdf), stdf),
('Order=%1.0f, \n' % (n), n),
('Damping=%1.3f%%, \n' % (d), d),
('CI Damping ± %1.3e, \n' % (stdd), stdd),
('MPC=%1.5f, \n' % (mpc), mpc),
('MP=%1.3f\u00b0, \n' % (mp), mp),
('MPD=%1.5f\u00b0, \n' % (mpd), mpd),
('dMP=%1.3f\u00b0, \n' % (dmp), dmp),
# ('dMPD=%1.5f\u00b0, \n' % (dmpd), dmpd),
('MTN=%1.5f, \n' % (mtn), mtn),
('MC=%1.5f, \n' % (MC), MC),
('Ext=%1.5f\u00b0, \n' % (ex_1), ex_1),
('Ext=%1.3f\u00b0, \n' % (ex_2), ex_2)
]:
if val is not np.nan:
s += text
self.current_value_view.setText(s)
height = self.current_value_view.document(
).size().toSize().height() + 3
self.current_value_view.setFixedHeight(height)
def update_stabil_view(self):
df_max = float(self.df_edit.text()) / 100
dd_max = float(self.dd_edit.text()) / 100
if self.stabil_calc.capabilities['std']:
stdf_max = float(self.stdf_edit.text()) / 100
else:
stdf_max = None
if self.stabil_calc.capabilities['std']:
stdd_max = float(self.stdd_edit.text()) / 100
else:
stdd_max = None
if self.stabil_calc.capabilities['msh']:
dmac_max = float(self.mac_edit.text()) / 100
else:
dmac_max = None
d_range = (
float(self.d_min_edit.text()), float(self.d_max_edit.text()))
if self.stabil_calc.capabilities['msh']:
mpc_min = float(self.mpc_edit.text())
mpd_max = float(self.mpd_edit.text())
else:
mpc_min = None
mpd_max = None
if self.stabil_calc.capabilities['MC']:
MC_min = float(self.MC_edit.text())
else:
MC_min = None
f_range = (float(self.freq_low.text()), float(self.freq_high.text()))
order_range = (int(self.n_low.text()), int(
self.n_step.text()), int(self.n_high.text()))
self.stabil_plot.update_stabilization(
df_max=df_max,
stdf_max=stdf_max,
dd_max=dd_max,
stdd_max=stdd_max,
dmac_max=dmac_max,
d_range=d_range,
mpc_min=mpc_min,
mpd_max=mpd_max,
MC_min=MC_min,
order_range=order_range
)
self.stabil_plot.update_xlim(f_range)
self.stabil_plot.update_ylim((order_range[0], order_range[2]))
if self.histo_plot_f is not None:
self.create_histo_plot_f()
if self.histo_plot_sf is not None:
self.create_histo_plot_sf()
if self.histo_plot_d is not None:
self.create_histo_plot_d()
if self.histo_plot_sd is not None:
self.create_histo_plot_sd()
if self.histo_plot_dr is not None:
self.create_histo_plot_dr()
if self.histo_plot_mac is not None:
self.create_histo_plot_mac()
if self.histo_plot_mpc is not None:
self.create_histo_plot_mpc()
if self.histo_plot_mpd is not None:
self.create_histo_plot_mpd()
def create_stab_val_widget(self, df_max=1, dd_max=5, d_mac=1,
d_range=(0, 5), mpc_min=0.9, mpd_max=15):
layout = QGridLayout()
layout.addWidget(QLabel('Stabilization Criteria'), 1, 1, 1, 3)
layout.setColumnStretch(2, 1)
i = 2
if self.stabil_calc.capabilities['f']:
layout.addWidget(QLabel('Frequency [%]'), i, 1)
self.df_edit = QLineEdit(str(df_max))
self.df_edit.setMaxLength(8)
self.df_edit.setFixedWidth(60)
layout.addWidget(self.df_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_f)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['std']:
layout.addWidget(QLabel('CoV F. [% of F]'), i, 1)
self.stdf_edit = QLineEdit('100')
self.stdf_edit.setMaxLength(8)
self.stdf_edit.setFixedWidth(60)
layout.addWidget(self.stdf_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_sf)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['d']:
layout.addWidget(QLabel('Damping[%]'), i, 1)
self.dd_edit = QLineEdit(str(dd_max))
self.dd_edit.setMaxLength(8)
self.dd_edit.setFixedWidth(60)
layout.addWidget(self.dd_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_d)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['std']:
layout.addWidget(QLabel('CoV D. [% of D]'), i, 1)
self.stdd_edit = QLineEdit('100')
self.stdd_edit.setMaxLength(8)
self.stdd_edit.setFixedWidth(60)
layout.addWidget(self.stdd_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_sd)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['msh']:
layout.addWidget(QLabel('MAC [%]'), i, 1)
self.mac_edit = QLineEdit(str(d_mac))
self.mac_edit.setMaxLength(8)
self.mac_edit.setFixedWidth(60)
layout.addWidget(self.mac_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_mac)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['d']:
layout.addWidget(QLabel('Damping range [%]'), i, 1)
self.d_min_edit = QLineEdit(str(d_range[0]))
self.d_min_edit.setMaxLength(8)
self.d_min_edit.setFixedWidth(60)
self.d_max_edit = QLineEdit(str(d_range[1]))
self.d_max_edit.setMaxLength(8)
self.d_max_edit.setFixedWidth(60)
lay = QHBoxLayout()
lay.addStretch()
lay.addWidget(self.d_min_edit)
lay.addWidget(QLabel('to'))
lay.addWidget(self.d_max_edit)
layout.addLayout(lay, i, 2, 1, 2)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_dr)
layout.addWidget(button, i, 4)
i += 1
layout.setRowStretch(i, 2)
i += 1
if self.stabil_calc.capabilities['msh']:
layout.addWidget(QLabel('MPC_min '), i, 1)
self.mpc_edit = QLineEdit(str(mpc_min))
self.mpc_edit.setMaxLength(8)
self.mpc_edit.setFixedWidth(60)
layout.addWidget(self.mpc_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_mpc)
layout.addWidget(button, i, 4)
i += 1
layout.addWidget(QLabel('MPD_max [°]'), i, 1)
self.mpd_edit = QLineEdit(str(mpd_max))
self.mpd_edit.setMaxLength(8)
self.mpd_edit.setFixedWidth(60)
layout.addWidget(self.mpd_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_mpd)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['mtn']:
layout.addWidget(QLabel('MTN_max []'), i, 1)
self.mtn_edit = QLineEdit('0')
self.mtn_edit.setMaxLength(8)
self.mtn_edit.setFixedWidth(60)
layout.addWidget(self.mtn_edit, i, 3)
button = QPushButton('Show Histo')
button.released.connect(self.create_histo_plot_mtn)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['MC']:
layout.addWidget(QLabel('MC_min []'), i, 1)
self.MC_edit = QLineEdit('0')
self.MC_edit.setMaxLength(8)
self.MC_edit.setFixedWidth(60)
layout.addWidget(self.MC_edit, i, 3)
button = QPushButton('Show MC')
button.setCheckable(True)
button.released.connect(self.show_MC_plot)
layout.addWidget(button, i, 4)
i += 1
if self.stabil_calc.capabilities['auto']:
b0 = QPushButton('Clear automatically')
b0.released.connect(self.prepare_auto_clearing)
self.num_iter_edit = QLineEdit(str(self.stabil_calc.num_iter))
layout.addWidget(b0, i, 1)
layout.addWidget(self.num_iter_edit, i, 2)
i += 1
b1 = QPushButton('Classify automatically')
b1.released.connect(self.prepare_auto_classification)
self.use_stabil_box = QCheckBox('Use Stabilization')
self.use_stabil_box.setTristate(False)
self.use_stabil_box.setChecked(False)
self.threshold_box = QLineEdit()
self.threshold_box.setPlaceholderText(
str(self.stabil_calc.threshold))
layout.addWidget(b1, i, 1)
layout.addWidget(self.use_stabil_box, i, 2)
layout.addWidget(self.threshold_box, i, 3)
i += 1
b2 = QPushButton('Select automatically')
b2.released.connect(self.prepare_auto_selection)
self.num_modes_box = QLineEdit(str(0))
layout.addWidget(b2, i, 1)
layout.addWidget(self.num_modes_box, i, 2)
return layout
def prepare_auto_clearing(self):
assert self.stabil_calc.capabilities['auto']
num_iter = int(self.num_iter_edit.text())
if isinstance(self.stabil_calc, StabilCluster):
self.stabil_calc.automatic_clearing(num_iter)
self.threshold_box.setPlaceholderText(
str(self.stabil_calc.threshold))
self.stabil_plot.update_stabilization()
self.check_clear.setChecked(True)
def prepare_auto_classification(self):
assert self.stabil_calc.capabilities['auto']
use_stabil = self.use_stabil_box.isChecked()
threshold = self.threshold_box.text()
# print(threshold, type(threshold), threshold.isnumeric())
if threshold.isnumeric():
threshold = float(threshold)
else:
threshold = None
if isinstance(self.stabil_calc, StabilCluster):
self.stabil_calc.automatic_classification(threshold, use_stabil)
self.check_select.setChecked(True)
def prepare_auto_selection(self):
assert self.stabil_calc.capabilities['auto']
num_modes = self.num_modes_box.text()
if num_modes.isnumeric():
num_modes = int(num_modes)
else:
num_modes = 0
for datapoint in reversed(self.stabil_calc.select_modes):
self.stabil_calc.remove_mode(datapoint)
print(self.stabil_calc.select_modes)
if isinstance(self.stabil_calc, StabilCluster):
self.stabil_calc.automatic_selection(num_modes)
# self.stabil_plot.update_stabilization()
# self.stabil_calc.plot_selection()
def create_diag_val_widget(
self,
show_sf=True,
show_sd=True,
show_sv=True,
show_sa=True,
show_all=True,
show_psd=False,
snap_to='sa',
f_range=(
0,
0),
n_range=(
0,
1,
0)):
layout = QGridLayout()
layout.addWidget(QLabel('View Settings'), 1, 1, 1, 2)
i = 2
check_sa = QCheckBox('Stable Pole')
check_sa.setChecked(show_sa)
self.stabil_plot.toggle_stable(show_sa)
check_sa.stateChanged.connect(self.stabil_plot.toggle_stable)
snap_sa = QRadioButton()
snap_sa.toggled.connect(self.snap_stable)
snap_sa.setChecked(snap_to == 'sa')
layout.addWidget(check_sa, i, 1)
layout.addWidget(snap_sa, i, 2)
i += 1
check_all = QCheckBox('All Poles')
check_all.setChecked(show_all)
self.stabil_plot.toggle_all(show_all)
check_all.stateChanged.connect(self.stabil_plot.toggle_all)
snap_all = QRadioButton()
snap_all.toggled.connect(self.snap_all)
snap_all.setChecked(snap_to == 'all')
layout.addWidget(check_all, i, 1)
layout.addWidget(snap_all, i, 2)
i += 1
if self.stabil_calc.capabilities['auto']:
show_clear = self.stabil_calc.state >= 3
check_clear = QCheckBox('AutoClear')
check_clear.setChecked(show_clear)
self.check_clear = check_clear
self.stabil_plot.toggle_clear(show_clear)
check_clear.stateChanged.connect(self.stabil_plot.toggle_clear)
snap_clear = QRadioButton()
snap_clear.toggled.connect(self.snap_clear)
snap_clear.setChecked(snap_to == 'clear')
layout.addWidget(check_clear, i, 1)
layout.addWidget(snap_clear, i, 2)
i += 1
show_select = self.stabil_calc.state >= 4
check_select = QCheckBox('AutoSelect')
check_select.setChecked(show_select)
self.check_select = check_select
self.stabil_plot.toggle_select(show_select)
check_select.stateChanged.connect(self.stabil_plot.toggle_select)
snap_select = QRadioButton()
snap_select.toggled.connect(self.snap_select)
snap_select.setChecked(snap_to == 'select')
layout.addWidget(check_select, i, 1)
layout.addWidget(snap_select, i, 2)
i += 1
if self.stabil_calc.capabilities['data']:
psd_check = QCheckBox('Show PSD')
psd_check.setChecked(show_psd)
self.stabil_plot.plot_sv_psd(show_psd)
psd_check.stateChanged.connect(self.stabil_plot.plot_sv_psd)
layout.addWidget(psd_check, i, 1, 1, 2)
i += 1
lay = QHBoxLayout()
lay.addWidget(QLabel('Freq. range:'))
if f_range[1] == 0:
f_range = (f_range[0], self.stabil_calc.get_max_f())
self.freq_low = QLineEdit('{:2.3f}'.format(f_range[0]))
self.freq_low.setFixedWidth(60)
self.freq_high = QLineEdit('{:2.3f}'.format(f_range[1] * 1.05))
self.freq_high.setFixedWidth(60)
lay.addWidget(self.freq_low)
lay.addWidget(QLabel('to'))
lay.addWidget(self.freq_high)
lay.addWidget(QLabel('[Hz]'))
layout.addLayout(lay, i, 1, 1, 2)
i += 1
lay = QHBoxLayout()
lay.addWidget(QLabel('Order. range (low:step:high):'))
if n_range[2] == 0:
n_range = (
n_range[0],
n_range[1],
self.stabil_calc.modal_data.max_model_order)
self.n_low = QLineEdit('{:2d}'.format(n_range[0]))
self.n_low.setFixedWidth(60)
self.n_step = QLineEdit('{:2d}'.format(n_range[1]))
self.n_step.setFixedWidth(60)
self.n_high = QLineEdit('{:2d}'.format(n_range[2]))
self.n_high.setFixedWidth(60)
lay.addWidget(self.n_low)
lay.addWidget(self.n_step)
lay.addWidget(self.n_high)
layout.addLayout(lay, i, 1, 1, 2)
i += 1
return layout
def save_figure(self, fname=None):
# copied and modified from
# matplotlib.backends.backend_qt4.NavigationToolbar2QT
canvas = self.stabil_plot.ax.figure.canvas
filetypes = canvas.get_supported_filetypes_grouped()
sorted_filetypes = sorted(filetypes.items())
# default_filetype = canvas.get_default_filetype()
startpath = rcParams.get('savefig.directory', '')
startpath = os.path.expanduser(startpath)
start = os.path.join(startpath, self.canvas.get_default_filename())
filters = []
for name, exts in sorted_filetypes:
exts_list = " ".join(['*.%s' % ext for ext in exts])
filter_ = '%s (%s)' % (name, exts_list)
filters.append(filter_)
filters = ';;'.join(filters)
if fname is None:
fname, ext = QFileDialog.getSaveFileName(
self, caption="Choose a filename to save to", directory=start, filter=filters)
# print(fname)
self.stabil_plot.save_figure(fname)
def save_results(self):
fname, fext = QFileDialog.getSaveFileName(self, caption="Choose a directory to save to",
directory=os.getcwd(), filter='Text File (*.txt)')
# fname, fext = os.path.splitext(fname)
if fext != 'txt':
fname += '.txt'
self.stabil_calc.export_results(fname)
def save_state(self):
fname, _ = QFileDialog.getSaveFileName(self, caption="Choose a directory to save to",
directory=os.getcwd(), filter='Numpy Archive File (*.npz)')
if fname == '':
return
fname, fext = os.path.splitext(fname)
if fext != 'npz':
fname += '.npz'
self.stabil_calc.save_state(fname)
self.close()
[docs]
def closeEvent(self, *args, **kwargs):
if self.msh_plot is not None:
self.msh_plot.mode_shape_plot.stop_ani()
# self.stabil_calc.select_modes = self.stabil_calc.select_modes
self.deleteLater()
return QMainWindow.closeEvent(self, *args, **kwargs)
[docs]
def keyPressEvent(self, e):
# print(e.key())
if e.key() == Qt.Key_Return or e.key() == Qt.Key_Enter:
self.update_stabil_view()
# print('2')
super().keyPressEvent(e)
[docs]
class ComplexPlot(QMainWindow):
[docs]
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle('Modeshapeplot in complex plane')
self.setGeometry(300, 300, 1000, 600)
main_frame = QWidget()
vbox = QVBoxLayout()
self.fig = Figure(facecolor='white', dpi=100, figsize=(4, 4))
self.canvas = FigureCanvasQTAgg(self.fig)
# self.canvas.setParent(main_frame)
vbox.addWidget(self.canvas, 10, Qt.AlignCenter)
main_frame.setLayout(vbox)
self.setCentralWidget(main_frame)
# self.show()
def scatter_this(self, msh, mp=None):
self.ax.cla()
self.ax.scatter(msh.real, msh.imag)
if mp is not None:
while mp < 0:
mp += 180
while mp > 360:
mp -= 360
mp = mp * np.pi / 180
xmin, xmax = -1, 1
ymin, ymax = -1, 1
if mp <= np.pi / 2:
x1 = max(xmin, ymin / np.tan(mp))
x2 = min(xmax, ymax / np.tan(mp))
y1 = max(ymin, xmin * np.tan(mp))
y2 = min(ymax, xmax * np.tan(mp))
elif mp <= np.pi:
x1 = max(xmin, ymax / np.tan(mp))
x2 = min(xmax, ymin / np.tan(mp))
y2 = max(ymin, xmax * np.tan(mp))
y1 = min(ymax, xmin * np.tan(mp))
elif mp <= 3 * np.pi / 2:
x1 = max(xmin, ymin / np.tan(mp))
x2 = min(xmax, ymax / np.tan(mp))
y1 = max(ymin, xmin * np.tan(mp))
y2 = min(ymax, xmax * np.tan(mp))
else:
x1 = max(xmin, ymax / np.tan(mp))
x2 = min(xmax, ymin / np.tan(mp))
y2 = max(ymin, xmax * np.tan(mp))
y1 = min(ymax, xmin * np.tan(mp))
self.ax.plot([x1, x2], [y1, y2])
lim = max(max(abs(msh.real)) * 1.1, max(abs(msh.imag)) * 1.1)
self.ax.set_xlim((-lim, lim))
self.ax.set_ylim((-lim, lim))
self.ax.spines['left'].set_position(('data', 0))
self.ax.spines['bottom'].set_position(('data', 0))
self.ax.spines['right'].set_position(('data', 0 - 1))
self.ax.spines['top'].set_position(('data', 0 - 1))
# Hide the line (but not ticks) for "extra" spines
for side in ['right', 'top']:
self.ax.spines[side].set_color('none')
# On both the x and y axes...
for axis, _ in zip([self.ax.xaxis, self.ax.yaxis], [0, 0]):
axis.set_minor_locator(ticker.NullLocator())
axis.set_major_formatter(ticker.NullFormatter())
self.fig.canvas.draw_idle()
def plot_diagram(self):
self.fig.set_tight_layout(True)
self.ax = self.fig.add_subplot(111)
self.ax.autoscale_view(tight=True)
# Set the axis's spines to be centered at the given point
# (Setting all 4 spines so that the tick marks go in both directions)
self.ax.spines['left'].set_position(('data', 0))
self.ax.spines['bottom'].set_position(('data', 0))
self.ax.spines['right'].set_position(('data', 0 - 1))
self.ax.spines['top'].set_position(('data', 0 - 1))
self.ax.xaxis.set_label('Re')
self.ax.yaxis.set_label('Im')
# Hide the line (but not ticks) for "extra" spines
for side in ['right', 'top']:
self.ax.spines[side].set_color('none')
# On both the x and y axes...
for axis, _ in zip([self.ax.xaxis, self.ax.yaxis], [0, 0]):
axis.set_minor_locator(ticker.NullLocator())
axis.set_major_formatter(ticker.NullFormatter())
self.fig.canvas.draw_idle()
# class ModeShapeWidget(object):
#
# def __init__(self, stabil_calc, modal_data, geometry_data, prep_data,**kwargs):
#
# #print(kwargs)
# super().__init__()
# #sys.path.append("/vegas/users/staff/womo1998/Projects/2016_Burscheid")
# #from main_Schwabach_2019 import print_mode_info
#
# self.mode_shape_plot = ModeShapePlot(
# stabil_calc=stabil_calc,
# modal_data=modal_data,
# geometry_data=geometry_data,
# prep_data=prep_data,
# amplitude=20,
# linewidth=0.5,
# #callback_fun=print_mode_info
# **kwargs)
# self.mode_shape_plot.show_axis = False
# # self.mode_shape_plot.draw_nodes()
# self.mode_shape_plot.draw_lines()
# # self.mode_shape_plot.draw_parent_childs()
# # self.mode_shape_plot.draw_chan_dofs()
#
# self.fig = self.mode_shape_plot.fig
# self.fig.set_size_inches((2, 2))
# self.canvas = self.fig.canvas.switch_backends(FigureCanvasQTAgg)
# self.mode_shape_plot.canvas = self.canvas
# self.fig.get_axes()[0].mouse_init()
# #self.canvas = self.mode_shape_plot.canvas
#
# for axis in [self.mode_shape_plot.subplot.xaxis, self.mode_shape_plot.subplot.yaxis, self.mode_shape_plot.subplot.zaxis]:
# axis.set_minor_locator(ticker.NullLocator())
# axis.set_major_formatter(ticker.NullFormatter())
# self.mode_shape_plot.animate()
#
#
#
# def plot_this(self, index):
# #self.mode_shape_plot.stop_ani()
# self.mode_shape_plot.change_mode(mode_index=index)
# #self.mode_shape_plot.animate()
[docs]
class HistoPlot(QMainWindow):
[docs]
def __init__(
self,
all_data,
stabil_data,
title='',
ranges=None,
select_ranges=[None],
select_callback=[None]):
QMainWindow.__init__(self)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setWindowTitle(title)
self.main_widget = QWidget(self)
l = QVBoxLayout(self.main_widget)
sc = MyMplCanvas(self.main_widget, width=5, height=2.5, dpi=100)
l.addWidget(sc)
m = QHBoxLayout()
m.addWidget(QLabel('min'))
if ranges is None:
ranges = (all_data.min(), all_data.max())
step = (ranges[1] - ranges[0]) / 50
self.lrange = DelayedDoubleSpinBox(decimals=8, singleStep=step)
self.lrange.setValue(ranges[0])
self.lrange.valueChangedDelayed.connect(self.update_range)
m.addWidget(self.lrange)
m.addWidget(QLabel('max'))
self.urange = DelayedDoubleSpinBox(decimals=8, singleStep=step)
self.urange.setValue(ranges[1])
self.urange.valueChangedDelayed.connect(self.update_range)
m.addWidget(self.urange)
l.addLayout(m)
self.axes = sc.axes
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
self.all_data = np.copy(all_data)
self.stabil_data = np.copy(stabil_data)
self.all_patches = None
self.stabil_patches = None
self.ranges = None
self.visible = True
self.select_ranges = select_ranges
self.select_callback = select_callback
self.selector_lines = []
# print('here in hist')
self.update_range()
def update_range(self, *args):
self.ranges = (self.lrange.value(), self.urange.value())
# print(self.ranges)
if self.ranges[0] >= self.ranges[1]:
return
if self.all_patches:
for patch in self.all_patches:
patch.remove()
n, self.bins, self.all_patches = self.axes.hist(
self.all_data, bins=50, color='blue', range=self.ranges)
self.axes.set_xlim(self.ranges)
self.axes.set_ylim((0, max(n) * 1.1))
self.axes.set_yticks([])
if self.select_callback[0] is not None and (
self.select_ranges[0] is not None or self.select_ranges[1] is not None) and not self.selector_lines:
for val in self.select_ranges:
if val is None:
self.selector_lines.append(None)
else:
line = self.axes.axvline(val, picker=5, color='red')
# print(line)
self.selector_lines.append(line)
self.axes.figure.canvas.mpl_connect(
'pick_event', self.on_pick_event)
self.axes.figure.canvas.mpl_connect(
"button_release_event", self.on_release_event)
self.axes.figure.canvas.mpl_connect(
"motion_notify_event", self.on_move_event)
self.dragged = None
self.update_histo(self.stabil_data)
def update_histo(self, stabil_data, select_ranges=None):
self.stabil_data = np.copy(stabil_data)
if self.stabil_patches:
for patch in self.stabil_patches:
patch.remove()
_, _, self.stabil_patches = self.axes.hist(
stabil_data, bins=self.bins, color='orange')
if self.selector_lines and select_ranges is not None:
# self.axes.figure.canvas.mpl_disconnect(self.connect_cid)
for val, line in zip(select_ranges, self.selector_lines):
if line is None:
continue
line.set_xdata(val)
self.axes.figure.canvas.draw_idle()
[docs]
def closeEvent(self, e):
self.visible = False
e.ignore()
self.hide()
def on_pick_event(self, event):
self.dragged = event.artist
self.pick_pos = (event.mouseevent.xdata, event.mouseevent.ydata)
return True
[docs]
def on_release_event(self, event):
" Update text position and redraw"
if self.dragged is not None:
xdata = event.xdata
if not xdata:
return False
# old_pos = self.dragged.get_xdata()
# new_pos = old_pos[0] + event.xdata - self.pick_pos[0]
self.dragged.set_xdata(xdata)
# print(self.dragged.get_xdata(), event.xdata)
ind = self.selector_lines.index(self.dragged)
self.select_callback[ind](xdata)
if len(self.selector_lines) == 1:
self.urange.setValue(xdata * 2)
self.urange.delayed_emit()
elif len(self.selector_lines) == 2:
delta_x = (self.ranges[0 if ind == 1 else 1] - xdata) / 2
[self.lrange, self.urange][ind].setValue(xdata - delta_x)
[self.lrange, self.urange][ind].delayed_emit()
self.dragged = None
self.axes.figure.canvas.draw_idle()
return True
[docs]
def on_move_event(self, event):
" Update text position and redraw"
if self.dragged is not None:
# old_pos = self.dragged.get_xdata()
# new_pos = old_pos[0] + event.xdata - self.pick_pos[0]
self.dragged.set_xdata(event.xdata)
# print(self.dragged.get_xdata(), event.xdata)
# self.dragged = None
self.axes.figure.canvas.draw_idle()
return True
[docs]
def nearly_equal(a, b, sig_fig=5):
return (a == b or
int(a * 10 ** sig_fig) == int(b * 10 ** sig_fig)
)
[docs]
def start_stabil_gui(
stabil_plot,
modal_data,
geometry_data=None,
prep_signals=None,
select_modes=[],
**kwargs):
# print(kwargs)
def handler(msg_type, msg_string):
pass
if 'app' not in globals().keys():
global app
app = QApplication(sys.argv)
if not isinstance(app, QApplication):
app = QApplication(sys.argv)
assert isinstance(stabil_plot, StabilPlot)
cmpl_plot = ComplexPlot()
if geometry_data is not None: # and prep_signals is not None:
mode_shape_plot = ModeShapePlot(stabil_calc=stabil_plot.stabil_calc,
modal_data=modal_data,
geometry_data=geometry_data,
prep_signals=prep_signals,
**kwargs)
msh_plot = ModeShapeGUI(mode_shape_plot, reduced_gui=True)
msh_plot.setGeometry(1000, 0, 800, 600)
msh_plot.reset_view()
msh_plot.hide()
else:
msh_plot = None
# qInstallMessageHandler(handler) #suppress unimportant error msg
stabil_gui = StabilGUI(stabil_plot, cmpl_plot, msh_plot)
# stabil_gui.cursor.add_datapoints(select_modes)
loop = QEventLoop()
stabil_gui.destroyed.connect(loop.quit)
loop.exec_()
FigureCanvasBase(stabil_plot.fig)
return
if __name__ == '__main__':
pass