def set_function_from_text(self, text: str) -> None: """ Set the function from text. Parameters: text: function expressed as a string. """ if text.strip() != "": function_name = text try: ani = self.canvas.get_animation() ani.set_function(function_name) except Exception as e: print(e) return self._setting_sliders = True self.destroy_sliders() d = ani.function.get_enumerated_default_values() for i in range(len(d)): symbol = d[i][0] value = d[i][1] slider_box = HorizontalSliderBox(self, symbol) self.control_widgets.addWidget(slider_box) slider_box.set_range(-10.0, 10.0) slider_box.set_number_of_ticks(2001) slider_box.set_observers([self]) slider_box.set_slider(value) self.sliders.append(slider_box) self.control_widgets.addWidget(self.circles_slider) self.control_widgets.addWidget(self.slider_speed) self._setting_sliders = False self.on_slider_changed({})
def place_variable_sliders(self, d): """ Place the variable sliders. Parameters: d: the dictionary of the variables and their values. """ for i in range(len(d)): symbol = d[i][0] value = d[i][1] slider_box = HorizontalSliderBox(self, symbol) slider_box.set_range(-10.0, 10.0) slider_box.set_number_of_ticks(2001) slider_box.set_observers([self]) slider_box.set_slider(value) self.widgets_layout.addWidget(slider_box) self.sliders.append(slider_box) self.widgets_layout.addWidget(self.speed_slider) self.widgets_layout.addWidget(self.resolution_slider)
class App(QtWidgets.QMainWindow): """ Main qt5 app. """ def __init__(self) -> None: """ Initializer. """ QtWidgets.QMainWindow.__init__(self) self.setWindowTitle("A simple GUI") self.menu_bar = self.menuBar() file_menu = self.menu_bar.addMenu('&file') file_menu.addAction("Save figure", lambda: self.canvas.get_animation( ).figure.savefig("figure.png")) file_menu.addAction("Quit", lambda : QtWidgets.QApplication.exit()) self.help = self.menu_bar.addMenu('&help') dialogue = QtWidgets.QMessageBox(self) # dialogue.aboutQt(self, "Title") self.message_box = dialogue self.help.addAction("instructions", self.show_instructions) self.help.addAction("about the GUI", self.show_about_gui) self.sliders = [] self._setting_sliders = False self.window = QtWidgets.QWidget(self) self.layout = QtWidgets.QHBoxLayout(self.window) rect = QtWidgets.QApplication.desktop().screenGeometry() self.canvas = Canvas(self, rect) color_name = self.window.palette().color( QtGui.QPalette.Background).name() self.canvas.get_animation().figure.patch.set_facecolor(color_name) # self.layout.addWidget(self.menu_bar) self.layout.addWidget(self.canvas) self.control_widgets = QtWidgets.QVBoxLayout() self.layout.addLayout(self.control_widgets) self._build_control_widgets() self.setCentralWidget(self.window) self.canvas.animation_loop() def _build_control_widgets(self): """ Build the control widgets. """ self.entry = HorizontalEntryBox( "Enter waveform f(t)") self.dropdown_dict = { "sine": "sin(t)", "cosine": "cos(t)", "gaussian": "3*exp(-t**2/(2*sigma**2 ))/2 - 1/2", "sinc": "3*sinc(k*(6.5)*t)/2 - 1/2", "rectangle": "3*rect(t)/2", "sawtooth": "t/pi", "triangle": "abs(t)" } dropdown_list = ["Preset Waveform f(t)"] dropdown_list.extend([key for key in self.dropdown_dict]) self.dropdown = QtWidgets.QComboBox(self) self.dropdown.addItems(dropdown_list) if hasattr(self.dropdown, "textActivated"): self.dropdown.textActivated.connect(self.on_dropdown_changed) else: self.dropdown.activated.connect(self.on_dropdown_changed) self.entry.set_observers([self]) self.circles_slider = HorizontalSliderBox(self, "Maximum Frequency") self.slider_speed = HorizontalSliderBox(self, "Speed") self.circles_slider.set_observers([self]) self.circles_slider.set_range(1, 80) self.circles_slider.set_value_string_format("%d") self.circles_slider.set_number_of_ticks(80) self.circles_slider.set_slider(80) self.slider_speed.set_observers([self]) self.slider_speed.set_range(-5, 5) self.slider_speed.set_value_string_format("%d") self.slider_speed.set_number_of_ticks(11) self.slider_speed.set_slider(1) # self.control_widgets.addWidget(self.mouse_dropdown) self.control_widgets.addWidget(self.dropdown) self.control_widgets.addWidget(self.entry) self.control_widgets.addWidget(self.circles_slider) self.control_widgets.addWidget(self.slider_speed) def show_instructions(self) -> None: """ Show instructions. """ message = ( "This app displays the (discrete) Fourier series of " "real, periodic, and well-behaved functions " "using rotating circles to represent each term. " "To visualize the Fourier Series for a different function, " "choose one of the preset functions in the " "Preset Waveform f(t) dropown menu, " "or enter a new function in the Enter waveform f(t) entry box. " "The function that you entered must be a function of t. " "This function can depend on other variables, where " "these variables are changed through sliders. " "Change the number of circles displayed by changing the value " "of the Maximum Frequency slider. " "To change the animation rate, use the Speed slider. " "Take a screenshot of the graph by selecting the " "file sidebar and clicking Save figure. " "To close the app, go to the file sidebar and select Quit." ) self.message_box.about(self, "Instructions", message) def show_about_gui(self) -> None: """ Show the about dialog. """ message = (r"The GUI is built using " r"<a href=https://wiki.qt.io/Qt_for_PythonPySide2>PySide2</a>," r" which is published under the" r" <a href=https://www.gnu.org/licenses/lgpl-3.0.en.html>LGPL</a>." ) self.message_box.about(self, "About", message) def on_dropdown_changed(self, text: Union[int, str]) -> None: """ Perform an action when the dropdown is changed. Parameters: text: either the index of the dropdown or text at the given index of the dropdown. """ if isinstance(text, str): if not text == "Preset Waveform f(t)": self.set_function_from_text(self.dropdown_dict[text]) elif isinstance(text, int): n = text text = self.dropdown.itemText(n) if not text == "Preset Waveform f(t)": self.set_function_from_text(self.dropdown_dict[text]) ani = self.canvas.get_animation() if text == "gaussian": ani.function_display.set_text(r"$f(t; \sigma) = " r"exp(-t^2/2 \sigma^2)$" r" , $ t = s (mod(2 \pi)) - \pi $" ) elif text == "sinc": ani.function_display.set_text(r"$f(t; k) = " r"sinc(kt)$" r" , $ t = s (mod(2 \pi)) - \pi $" ) else: ani.function_display.set_text(r"$f(t)$" r" , $ t = s (mod(2 \pi)) - \pi $" ) def set_function_from_text(self, text: str) -> None: """ Set the function from text. Parameters: text: function expressed as a string. """ if text.strip() != "": function_name = text try: ani = self.canvas.get_animation() ani.set_function(function_name) except Exception as e: print(e) return self._setting_sliders = True self.destroy_sliders() d = ani.function.get_enumerated_default_values() for i in range(len(d)): symbol = d[i][0] value = d[i][1] slider_box = HorizontalSliderBox(self, symbol) self.control_widgets.addWidget(slider_box) slider_box.set_range(-10.0, 10.0) slider_box.set_number_of_ticks(2001) slider_box.set_observers([self]) slider_box.set_slider(value) self.sliders.append(slider_box) self.control_widgets.addWidget(self.circles_slider) self.control_widgets.addWidget(self.slider_speed) self._setting_sliders = False self.on_slider_changed({}) def on_slider_changed(self, slider_input: dict) -> None: """ When the slider is changed perform some action. Parameters: slider_input: a dictionary containing information about the slider. """ if 'id' in slider_input and isinstance(slider_input['id'], str): ani = self.canvas.get_animation() if slider_input['id'] == "Speed": ani.set_speed(slider_input['value']) elif slider_input['id'] == "Maximum Frequency": ani.set_number_of_circles(int(slider_input['value'])+1) else: params = [] if self.sliders != [] and not self._setting_sliders: for slider in self.sliders: info = slider.get_slider_info() params.append(info['value']) ani = self.canvas.get_animation() ani.set_params(*params) def destroy_sliders(self) -> None: """ Destroy the sliders. """ while self.sliders: slider_box = self.sliders.pop() self.control_widgets.removeWidget(slider_box) self.layout.removeWidget(slider_box) slider_box.destroy_slider() slider_box.close() self.control_widgets.removeWidget(self.circles_slider) self.control_widgets.removeWidget(self.slider_speed) def on_entry_returned(self, text: str) -> None: """ Perform an action when the enter function is pressed. Parameters: text: a string from an entry box. """ self.set_function_from_text(text)
class App(QtWidgets.QMainWindow): """ Main qt5 app. """ def __init__(self) -> None: """ Initializer. """ QtWidgets.QMainWindow.__init__(self) self.setWindowTitle("A simple GUI") self.sliders = [] self.window = QtWidgets.QWidget(self) self.layout = QtWidgets.QHBoxLayout(self.window) rect = QtWidgets.QApplication.desktop().screenGeometry() self.canvas = Canvas(self, rect) color_name = self.window.palette().color( QtGui.QPalette.Background).name() self.canvas.get_animation().figure.patch.set_facecolor(color_name) self.layout.addWidget(self.canvas) self.setCentralWidget(self.window) self.canvas.animation_loop() self.speed_slider = HorizontalSliderBox(self, "Animation Speed ") self.resolution_slider = HorizontalSliderBox(self, "Number of circles ") self.mouse_dropdown = QtWidgets.QComboBox(self) self.mouse_dropdown.addItems(["Mouse: ", "Move plot view", "Draw line"]) self.mouse_dropdown.activated.connect(self.on_mouse_dropdown_changed) self.widgets_layout = QtWidgets.QVBoxLayout(self.window) self.layout.addLayout(self.widgets_layout) self.widgets_layout.addWidget(self.mouse_dropdown) self.xy_entry = DoubleHorizontalEntryBox("Set x(t)", "Set y(t)") self.xy_entry.set_observers([self.canvas.get_animation(), self]) self.sliders = [] self.widgets_layout.addWidget(self.xy_entry) self.widgets_layout.addWidget(self.speed_slider) self.speed_slider.set_number_of_ticks(201) self.speed_slider.set_range(-100, 100) self.speed_slider.set_slider(20.0) self.speed_slider.set_observers([self]) self.speed_slider.set_value_string_format("%d") self.widgets_layout.addWidget(self.resolution_slider) self.resolution_slider.set_number_of_ticks(100) self.resolution_slider.set_range(1, 100) self.resolution_slider.set_slider(100) self.resolution_slider.set_value_string_format("%d") self.resolution_slider.set_observers([self]) def on_mouse_dropdown_changed(self, index: int) -> None: """ On mouse dropdown changed Parameters: index: index of the mouse change. """ self.canvas.set_mouse_usage(index) def on_entry_returned(self, entry_info) -> None: """ On entry returned Parameters: entry_info: the dictionary containing info about the entry. """ ani = self.canvas.get_animation() n = ani.get_number_of_points() self.resolution_slider.set_range(1, n-1) self.resolution_slider.set_number_of_ticks(n-1) self.resolution_slider.set_slider(n-1) ft = ani.get_functions() def_val = ft.get_enumerated_default_values() self.destroy_sliders() self.place_variable_sliders(def_val) def place_variable_sliders(self, d): """ Place the variable sliders. Parameters: d: the dictionary of the variables and their values. """ for i in range(len(d)): symbol = d[i][0] value = d[i][1] slider_box = HorizontalSliderBox(self, symbol) slider_box.set_range(-10.0, 10.0) slider_box.set_number_of_ticks(2001) slider_box.set_observers([self]) slider_box.set_slider(value) self.widgets_layout.addWidget(slider_box) self.sliders.append(slider_box) self.widgets_layout.addWidget(self.speed_slider) self.widgets_layout.addWidget(self.resolution_slider) def destroy_sliders(self) -> None: """ Destroy the sliders of the entry inputs. """ while self.sliders: slider_box = self.sliders.pop() self.widgets_layout.removeWidget(slider_box) self.layout.removeWidget(slider_box) slider_box.destroy_slider() slider_box.close() self.widgets_layout.removeWidget(self.speed_slider) self.widgets_layout.removeWidget(self.resolution_slider) def on_slider_changed(self, slider_dict) -> None: """ On slider changed. Parameters: slider_dict: dictionary containing information about the slider. """ if slider_dict['id'] == "Animation Speed ": speed = slider_dict['value'] self.canvas.get_animation().set_animation_speed(speed) elif slider_dict['id'] == "Number of circles ": resolution = slider_dict['value'] self.canvas.get_animation().set_circle_resolution(int(resolution)+1) elif self.sliders != []: params = [] for slider in self.sliders: info = slider.get_slider_info() params.append(info['value']) ani = self.canvas.get_animation() ani.set_params(*params)