def showWindow(self): self.setGeometry(300, 300, 300, 63) self.setFixedSize(self.size()) self.setWindowIcon(QIcon("icon.png")) self.setWindowTitle("pyWall UI") global btn btn = QPushButton("Change", self) btn.resize(75, 23) btn.move(0, self.height() - btn.height()) btn.setToolTip("Change the wallpaper right now.") btn.clicked.connect(newWallpaperInNewThread) global txtinterval txtinterval = QTextEdit("100", self) txtinterval.setToolTip("Time interval in seconds between wallpaper changes.") txtinterval.resize(70, 23) txtinterval.move(0, btn.y() - txtinterval.height()) global chkbox chkbox = QCheckBox("Timer", self) chkbox.setToolTip("Use timer for auto wallpaper change.") chkbox.resize(49, 17) chkbox.move(0, txtinterval.y() - chkbox.height()) chkbox.stateChanged.connect(checkBoxStateChanged) global label label = QLabel("", self) label.setFont(QFont("Times", 8, QFont.Bold)) label.move(btn.width() + 5, 0) label.resize(self.width()-btn.width(),self.height()) label.setWordWrap(True) self.show()
class WebFilesTransmitterBox(QGroupBox): showm_signal = pyqtSignal(str) def __init__(self, WebFilesTransmitter: WebFilesTransmitter, text="", parent=None): super(WebFilesTransmitterBox, self).__init__(text, parent) self.WebFilesTransmitter = WebFilesTransmitter self.transmitter_web_start_btn = QPushButton("开始共享", self) self.transmitter_web_start_btn.setGeometry(5, 22, 80, 28) self.transmitter_web_start_btn.clicked.connect(self.changeshare) # self.WebFilesTransmitter.start_btn_ss_signal.connect(self.transmitter_web_start_btn.setStyleSheet) self.transmitter_reset_web_port_btn = QPushButton("重置端口", self) self.transmitter_reset_web_port_btn.setGeometry(self.transmitter_web_start_btn.x(), self.transmitter_web_start_btn.y() + self.transmitter_web_start_btn.height() + 10, self.transmitter_web_start_btn.width(), self.transmitter_web_start_btn.height()) self.transmitter_reset_web_port_btn.clicked.connect(self.resetport) self.transmitter_reset_web_port_btn.setToolTip("重置端口并重启服务,此前的链接将不可以!") self.transmitter_web_allowupload = QCheckBox("允许上传", self) self.transmitter_web_allowupload.setToolTip("允许网页端上传文件,文件将保存于共享的文件夹内") self.transmitter_web_allowupload.setStatusTip("允许网页端上传文件,文件将保存于共享的文件夹内") self.transmitter_web_allowupload.setChecked( QSettings('Fandes', 'jamtools').value('transmitter/allowupload', True, type=bool)) self.transmitter_web_allowupload.move(self.transmitter_reset_web_port_btn.x() + 2, self.transmitter_reset_web_port_btn.y() + self.transmitter_reset_web_port_btn.height() + 15) def allowuploadchange(a): try: self.WebFilesTransmitter.http_handler.canupload = True if a else False except: pass self.WebFilesTransmitter.canupload = True if a else False QSettings('Fandes', 'jamtools').setValue('transmitter/allowupload', self.transmitter_web_allowupload.isChecked()) if self.WebFilesTransmitter.sharing: self.showm_signal.emit("已{}网页端文件上传".format("允许" if a else "禁止")) self.transmitter_web_allowupload.stateChanged.connect(allowuploadchange) self.transmitter_web_need_login = QCheckBox("需要密码", self) self.transmitter_web_need_login.setToolTip("需要先登录") self.transmitter_web_need_login.setStatusTip("需要先用密码登录") self.transmitter_web_need_login.move(self.transmitter_web_allowupload.x(), self.transmitter_web_allowupload.y() + self.transmitter_web_allowupload.height() + 5) def need_loginchange(a): try: self.WebFilesTransmitter.http_handler.need_login = True if a else False except: pass self.WebFilesTransmitter.need_login = True if a else False self.transmitter_web_need_login.setChecked(a) self.transmitter_web_need_login_label.setVisible(bool(a)) QSettings('Fandes', 'jamtools').setValue('transmitter/need_login', self.transmitter_web_need_login.isChecked()) self.transmitter_web_need_login.stateChanged.connect(need_loginchange) self.transmitter_web_need_login_label = QLineEdit(self) self.transmitter_web_need_login_label.setGeometry(self.transmitter_web_need_login.x(), self.transmitter_web_need_login.y() + self.transmitter_web_need_login.height() - 10, self.transmitter_web_need_login.width() - 10, 25) self.transmitter_web_need_login_label.setPlaceholderText("1234") self.transmitter_web_need_login_label.textChanged.connect( lambda x: QSettings('Fandes', 'jamtools').setValue('transmitter/login_password', x if len(x) else "1234")) self.transmitter_web_need_login_label.setText( QSettings('Fandes', 'jamtools').value('transmitter/login_password', "1234")) need_loginchange(QSettings('Fandes', 'jamtools').value('transmitter/need_login', True, type=bool)) self.transmitter_web_info = WebFilesTransmitter_infolabel(self) self.transmitter_web_info.showm_signal.connect(self.showm_signal.emit) self.transmitter_web_info.setGeometry( self.transmitter_web_start_btn.x() + self.transmitter_web_start_btn.width() + 15, self.transmitter_web_start_btn.y(), 500, 200) print(self.transmitter_web_info.isVisible(), self.transmitter_web_info.size(), 500, "vis") def choicefiles(): files, l = QFileDialog.getOpenFileNames(self, "选择要共享的文件", "", "all files(*.*);;") print(files) if len(files): self.WebFilesTransmitter.show_some_files(files, self.transmitter_web_allowupload.isChecked(), self.transmitter_web_need_login.isChecked()) self.transmitter_web_info.sharepath = os.path.split(files[0])[0] + "/{}个文件".format(len(files)) QSettings('Fandes', 'jamtools').setValue('transmitter/sharepath', os.path.split(files[0])[0]) def choicedir(): dir = QFileDialog.getExistingDirectory(self, "选择要共享的文件夹", QSettings('Fandes', 'jamtools').value('transmitter/sharepath', "", str)) print(dir) if len(dir): self.WebFilesTransmitter.show_a_dir(dir, self.transmitter_web_allowupload.isChecked(), self.transmitter_web_need_login.isChecked()) self.transmitter_web_info.sharepath = dir self.transmitter_web_info.update() QSettings('Fandes', 'jamtools').setValue('transmitter/sharepath', dir) self.transmitter_web_choice_files = QPushButton("选择文件", self) self.transmitter_web_choice_files.clicked.connect(choicefiles) self.transmitter_web_choice_files.setToolTip("选择一个文件夹内的多个文件共享") self.transmitter_web_choice_files.setStatusTip("选择一个文件夹内的多个文件共享") self.transmitter_web_choice_dir = QPushButton("选择文件夹", self) self.transmitter_web_choice_dir.clicked.connect(choicedir) self.transmitter_web_choice_dir.setToolTip("选择一个文件夹,共享整个文件夹包括其子文件夹") self.transmitter_web_choice_dir.setStatusTip("选择一个文件夹,共享整个文件夹包括其子文件夹") self.transmitter_web_choice_files.setGeometry(280, 20, 80, 23) self.transmitter_web_choice_dir.setGeometry(self.transmitter_web_choice_files.x(), self.transmitter_web_choice_files.y() + self.transmitter_web_choice_files.height(), self.transmitter_web_choice_files.width(), self.transmitter_web_choice_files.height()) self.transmitter_web_devices = QComboBox(self) self.transmitter_web_devices.setGeometry(190, 80, 140, 23) self.transmitter_web_devices.setToolTip("请选择要生成链接的网卡,设备需要连入共同网段才可访问共享文件,\n" "例如:本机已通过以太网连入校园网时,可选择以太网适配器生成链接和二维码,\n" "另一台已经连入该校园网的设备就可以通过链接或扫描二维码访问共享文件") self.transmitter_web_devices.setStatusTip("多网卡用户请选择要生成链接的网卡,设备需要连入共同网段才可访问共享文件") self.transmitter_web_devices.currentTextChanged.connect( lambda x: self.transmitter_web_info.set_info(self.WebFilesTransmitter.sharepath, self.WebFilesTransmitter.devicedict[x], self.WebFilesTransmitter.port) if x != "" else None) update_btn = QPushButton(QIcon(":/update.png"), "", self) update_btn.setToolTip("刷新设备,如改变了wifi/移动热点请刷新一下以获取正确的链接") update_btn.setGeometry(self.transmitter_web_devices.x() + self.transmitter_web_devices.width() + 5, self.transmitter_web_devices.y(), 20, 20) update_btn.clicked.connect(self.updatedevice) d = QSettings('Fandes', 'jamtools').value('transmitter/sharepath', "") if d != "": self.WebFilesTransmitter.show_a_dir(d, self.transmitter_web_allowupload.isChecked(), self.transmitter_web_need_login.isChecked()) self.transmitter_web_info.sharepath = d def changeshare(self): if self.transmitter_web_info.sharepath == "请先选择要共享的文件": self.showm_signal.emit("未选择要共享的路径/文件!") print("未选择要共享的路径") return if self.WebFilesTransmitter.sharing: print("停止共享") self.transmitter_web_start_btn.setStyleSheet("QPushButton{background-color:rgb(239,239,239);}") self.transmitter_web_start_btn.setText("开始共享") self.WebFilesTransmitter.stop_server() else: self.transmitter_web_start_btn.setStyleSheet("QPushButton{background-color:rgb(255,50,50);}") self.transmitter_web_start_btn.setText("结束共享") self.WebFilesTransmitter.start() print("开始共享") def resetport(self): sharing = self.WebFilesTransmitter.sharing if sharing: try: self.changeshare() except: print(sys.exc_info()) self.WebFilesTransmitter.port = random.randint(6048, 65530) QSettings('Fandes', 'jamtools').setValue("webtransmitterport", self.WebFilesTransmitter.port) if sharing: self.WebFilesTransmitter.wait() self.changeshare() self.updatedevice() def updatedevice(self): # print("baseppppppppppppp", sys.path) self.transmitter_web_devices.clear() self.transmitter_web_devices.addItems(self.WebFilesTransmitter.get_alldevices().keys())
class MainWindow(QWidget): """Окно графического интерфейса""" def __init__(self): super().__init__() self.sim = PendulumLearning( self ) # Объект с моделью и обучающейся системой управления маятником # Элементы интерфейса self.canvas_width = 800 # Ширина холста self.canvas_height = 675 # Длина холста self.canvas = Plotter(self.canvas_width, self.canvas_height, dpi=100, parent=self) # Холст с графиками # Кнопки self.start_button = QPushButton('Start', self) self.stop_button = QPushButton('Stop', self) self.restart_button = QPushButton('Restart', self) self.new_nn_button = QPushButton('New neural net', self) self.load_nn_button = QPushButton('Load neural net', self) self.save_nn_button = QPushButton('Save neural net', self) self.save_plots_button = QPushButton('Save plots', self) self.clear_button = QPushButton('Clear', self) # Надписи self.eps_start_label = QLabel('Initial probability\nof random action', self) self.eps_discount_label = QLabel( 'Discount of probability\non each step', self) self.eps_final_label = QLabel('Final probability\nof random action', self) self.episode_length_label = QLabel('Episode length', self) self.batch_size_label = QLabel('Training batch\nsize', self) # Поля ввода чисел self.eps_start_spinbox = QDoubleSpinBox(self) self.eps_discount_spinbox = QDoubleSpinBox(self) self.eps_final_spinbox = QDoubleSpinBox(self) self.episode_length_spinbox = QSpinBox(self) self.batch_size_spinbox = QSpinBox(self) # Кнопки выбора обучающейся модели self.q_learning_rb = QRadioButton("Deep Q-learning", self) self.q_learning2_rb = QRadioButton("Q-learning, net with one output", self) self.actor_critic_rb = QRadioButton("Adaptive critic", self) self.actor_critic_DDPG_rb = QRadioButton("Adaptive critic (DDPG)", self) # Чекбоксы self.eps_greedy_checkbox = QCheckBox("Use random actions", self) self.learning_checkbox = QCheckBox("Turn training on", self) self.endless_episode_checkbox = QCheckBox("Endless episode", self) # Вывод данных self.output_text_field = QTextBrowser(self) self.initUI() def initUI(self): """Формирование интерфейса""" size = (1300, 715) # Размер окна position = (100, 100) # Начальная позиция окна canvas_position = (20, 20) # Верхний левый угол холста buttons_indent = 10 # Расстояние между кнопками spinbox_indent = 8 # Расстояние между полями выбора чисел labels_indent = 5 # Расстояние между надписями # Параметры поля выбора начальной вероятности выбора случайного действия eps_start_min = 0 eps_start_max = 1 eps_start_step = 0.1 eps_start_default_value = 0.5 # Параметры поля выбора шага уменьшения вероятности случайного действия eps_discount_min = 0 eps_discount_max = 1 eps_discount_step = 0.000001 eps_discount_default_value = 0.00002 eps_discount_decimals = 6 # Параметры поля выбора конечной вероятности выбора случайного действия eps_final_min = 0 eps_final_max = 1 eps_final_step = 0.01 eps_final_default_value = 0.05 # Параметры поля выбора длины эпизода episode_length_min = 1 episode_length_max = 2000 episode_length_step = 100 episode_length_default_value = 200 # Параметры поля выбора размера пачки при обучении batch_size_min = 1 batch_size_max = 300 batch_size_step = 10 batch_size_default_value = 50 # Размер поля вывода данных text_field_size = (460, 170) buttons_left = canvas_position[ 0] + buttons_indent + self.canvas_width # Координата левого края блока элементов управления buttons_up = canvas_position[ 1] # Координата верхнего края блока элементов управления # Изменяем позицию и перемещаем окно self.resize(*size) self.move(*position) self.canvas.move(*canvas_position) # Кнопки старт, стоп, перезапуск button_up = buttons_up # Верхняя позиция текущей кнопки self.start_button.resize(self.start_button.sizeHint()) self.start_button.move(buttons_left, button_up) self.start_button.clicked.connect(self.start) buttons_distance = self.start_button.height( ) + buttons_indent # Расстояние между верхними позициями кнопок spinbox_distance = self.eps_start_spinbox.height() + spinbox_indent button_up += buttons_distance self.stop_button.resize(self.start_button.sizeHint()) self.stop_button.move(buttons_left, button_up) self.stop_button.clicked.connect(self.stop) button_up += buttons_distance self.restart_button.resize(self.start_button.sizeHint()) self.restart_button.move(buttons_left, button_up) self.restart_button.clicked.connect(self.restart) # Элементы для настройки случайных действий # Координата левого края блока элементов для генерации случайной среды controls_left = buttons_left + self.start_button.width( ) + buttons_indent element_up = buttons_up # Верхняя позиция текущего элемента управления self.eps_start_label.resize(self.eps_start_label.sizeHint()) self.eps_start_label.move(controls_left, element_up) element_left = controls_left + self.eps_start_label.width( ) + buttons_indent self.eps_start_spinbox.move(element_left, element_up) self.eps_start_spinbox.setMinimum(eps_start_min) self.eps_start_spinbox.setMaximum(eps_start_max) self.eps_start_spinbox.setSingleStep(eps_start_step) self.eps_start_spinbox.setValue(eps_start_default_value) self.eps_start_spinbox.valueChanged.connect(self.change_start_eps) self.change_start_eps() element_up += spinbox_distance self.eps_final_label.resize(self.eps_final_label.sizeHint()) self.eps_final_label.move(controls_left, element_up) element_left = controls_left + self.eps_final_label.width( ) + buttons_indent self.eps_final_spinbox.move(element_left, element_up) self.eps_final_spinbox.setMinimum(eps_final_min) self.eps_final_spinbox.setMaximum(eps_final_max) self.eps_final_spinbox.setSingleStep(eps_final_step) self.eps_final_spinbox.setValue(eps_final_default_value) self.eps_final_spinbox.valueChanged.connect(self.change_final_eps) self.change_final_eps() element_up += spinbox_distance self.eps_discount_label.resize(self.eps_discount_label.sizeHint()) self.eps_discount_label.move(controls_left, element_up) element_left = controls_left + self.eps_discount_label.width( ) + buttons_indent self.eps_discount_spinbox.setDecimals(eps_discount_decimals) self.eps_discount_spinbox.resize(self.eps_discount_spinbox.sizeHint()) self.eps_discount_spinbox.move(element_left, element_up) self.eps_discount_spinbox.setMinimum(eps_discount_min) self.eps_discount_spinbox.setMaximum(eps_discount_max) self.eps_discount_spinbox.setSingleStep(eps_discount_step) self.eps_discount_spinbox.setValue(eps_discount_default_value) self.eps_discount_spinbox.valueChanged.connect( self.change_eps_discount) self.change_eps_discount() element_up += spinbox_distance self.eps_greedy_checkbox.resize(self.eps_greedy_checkbox.sizeHint()) self.eps_greedy_checkbox.move(controls_left, element_up) self.eps_greedy_checkbox.setChecked(True) self.eps_greedy_checkbox.stateChanged.connect(self.toggle_eps_greedy) self.toggle_eps_greedy() labels_distance = self.eps_greedy_checkbox.height() + labels_indent element_up += labels_distance button_up = max([element_up, button_up]) self.q_learning_rb.move(buttons_left, button_up) self.q_learning_rb.setChecked(True) self.q_learning_rb.toggled.connect(self.select_learning_model) button_up += labels_distance self.q_learning2_rb.move(buttons_left, button_up) self.q_learning2_rb.toggled.connect(self.select_learning_model) button_up += labels_distance self.actor_critic_rb.move(buttons_left, button_up) self.actor_critic_rb.toggled.connect(self.select_learning_model) button_up += labels_distance self.actor_critic_DDPG_rb.move(buttons_left, button_up) self.actor_critic_DDPG_rb.toggled.connect(self.select_learning_model) self.select_learning_model() button_up += labels_distance self.learning_checkbox.move(buttons_left, button_up) self.learning_checkbox.setChecked(True) self.learning_checkbox.stateChanged.connect(self.toggle_learning) self.toggle_learning() button_up += labels_distance self.batch_size_label.resize(self.batch_size_label.sizeHint()) self.batch_size_label.move(buttons_left, button_up) element_left = buttons_left + self.batch_size_label.width( ) + buttons_indent self.batch_size_spinbox.resize(self.batch_size_spinbox.sizeHint()) self.batch_size_spinbox.move(element_left, button_up) self.batch_size_spinbox.setMinimum(batch_size_min) self.batch_size_spinbox.setMaximum(batch_size_max) self.batch_size_spinbox.setSingleStep(batch_size_step) self.batch_size_spinbox.setValue(batch_size_default_value) self.batch_size_spinbox.valueChanged.connect(self.change_batch_size) self.change_batch_size() button_up += spinbox_distance element_up = button_up self.new_nn_button.resize(self.save_nn_button.sizeHint()) self.new_nn_button.move(buttons_left, button_up) self.new_nn_button.clicked.connect(self.new_nn) button_up += buttons_distance self.load_nn_button.resize(self.save_nn_button.sizeHint()) self.load_nn_button.move(buttons_left, button_up) self.load_nn_button.clicked.connect(self.load_nn) button_up += buttons_distance self.save_nn_button.resize(self.save_nn_button.sizeHint()) self.save_nn_button.move(buttons_left, button_up) self.save_nn_button.clicked.connect(self.save_nn) button_up += buttons_distance elements_left = buttons_left + self.save_nn_button.width( ) + buttons_indent self.save_plots_button.resize(self.save_plots_button.sizeHint()) self.save_plots_button.move(elements_left, element_up) self.save_plots_button.clicked.connect(self.save_plots) element_up += buttons_distance self.clear_button.resize(self.save_plots_button.sizeHint()) self.clear_button.move(elements_left, element_up) self.clear_button.clicked.connect(self.clear) element_up += buttons_distance self.episode_length_label.resize(self.episode_length_label.sizeHint()) self.episode_length_label.move(buttons_left, button_up) element_left = buttons_left + self.episode_length_label.width( ) + buttons_indent self.episode_length_spinbox.resize( self.episode_length_spinbox.sizeHint()) self.episode_length_spinbox.move(element_left, button_up) self.episode_length_spinbox.setMinimum(episode_length_min) self.episode_length_spinbox.setMaximum(episode_length_max) self.episode_length_spinbox.setSingleStep(episode_length_step) self.episode_length_spinbox.setValue(episode_length_default_value) self.episode_length_spinbox.valueChanged.connect( self.change_episode_length) self.change_episode_length() button_up += spinbox_distance self.endless_episode_checkbox.move(buttons_left, button_up) self.endless_episode_checkbox.setChecked(False) self.endless_episode_checkbox.stateChanged.connect( self.toggle_endless_episode) self.toggle_endless_episode() button_up += labels_distance self.output_text_field.resize(*text_field_size) self.output_text_field.move(buttons_left, button_up) self.output_text_field.setReadOnly(True) self.setWindowTitle('An Inverted Pendulum') self.show() def closeEvent(self, event): """Закрытие окна""" self.sim.exit() self.deleteLater() self.close() def start(self): """Запуск моделирования""" self.sim.start() def stop(self): """Остановка моделирования""" self.sim.stop() def restart(self): """Поместить маятник в случайную позицию""" self.sim.restart() def change_start_eps(self): """Изменить начальную вероятность случайного действия""" self.sim.set_eps(self.eps_start_spinbox.value()) def change_final_eps(self): """Изменить конечную вероятность случайного действия""" self.sim.set_final_eps(self.eps_final_spinbox.value()) def change_eps_discount(self): """Изменить шаг уменьшения вероятности случайного действия""" self.sim.set_eps_discount(self.eps_discount_spinbox.value()) def select_learning_model(self): """Выбрать обучающуюся модель""" if self.q_learning_rb.isChecked(): lm_number = 0 elif self.q_learning2_rb.isChecked(): lm_number = 1 elif self.actor_critic_rb.isChecked(): lm_number = 2 else: lm_number = 3 self.sim.choose_learning_model(lm_number) def toggle_eps_greedy(self): """Включить или отключить совершение случайных действий""" self.sim.set_eps_greedy(self.eps_greedy_checkbox.isChecked()) def toggle_learning(self): """Производить ли обучение модели, или просто включить управление""" enable = self.learning_checkbox.isChecked() self.sim.is_learning = enable def save_plots(self): """Сохранить графики в файл""" file_dialogue = QFileDialog() file_dialogue.setFileMode(QFileDialog.AnyFile) file_dialogue.setAcceptMode(QFileDialog.AcceptSave) name_filters = ["PNG images (*.png)", "All files (*.*)"] file_dialogue.setNameFilters(name_filters) if file_dialogue.exec(): filename = file_dialogue.selectedFiles()[0] try: self.canvas.figure.savefig(filename) except PermissionError as e: QMessageBox.warning(self, "Error", str(e)) self.canvas.draw() file_dialogue.deleteLater() def change_batch_size(self): """Изменить размер пачки при обучении нейросетей""" self.sim.set_batch_size(self.batch_size_spinbox.value()) def new_nn(self): """Создать новую нейросеть со случайными коэффициентами""" self.sim.new_nn() # Создать новую нейросеть и очистить опыт self.change_start_eps() # Обновить вероятность случайного действия def load_nn(self): """Загрузить нейросеть из файла""" file_dialogue = QFileDialog() file_dialogue.setFileMode(QFileDialog.ExistingFile) file_dialogue.setAcceptMode(QFileDialog.AcceptOpen) if self.actor_critic_rb.isChecked( ) or self.actor_critic_DDPG_rb.isChecked(): name_filters = ["TensorFlow session (*.meta)"] else: name_filters = [ "Hierarchical data format (*.hdf)", "All files (*.*)" ] file_dialogue.setNameFilters(name_filters) if file_dialogue.exec(): filename = file_dialogue.selectedFiles()[0] try: self.sim.load_nn(filename) except OSError or FileNotFoundError or FileNotFoundError as e: QMessageBox.warning(self, "Error", str(e)) file_dialogue.deleteLater() def save_nn(self): """Сохранить нейросеть в файл""" file_dialogue = QFileDialog() file_dialogue.setFileMode(QFileDialog.AnyFile) file_dialogue.setAcceptMode(QFileDialog.AcceptSave) if self.actor_critic_rb.isChecked( ) or self.actor_critic_DDPG_rb.isChecked(): name_filters = ["TensorFlow session (*.*)"] else: name_filters = [ "Hierarchical data format (*.hdf)", "All files (*.*)" ] file_dialogue.setNameFilters(name_filters) if file_dialogue.exec(): filename = file_dialogue.selectedFiles()[0] try: self.sim.save_nn(filename) except PermissionError as e: QMessageBox.warning(self, "Error", str(e)) file_dialogue.deleteLater() def change_episode_length(self): """Изменить длину эпизода - количества шагов перед случайным выбором новой позиции маятника""" episode_length = self.episode_length_spinbox.value() self.sim.max_ep_steps = episode_length def toggle_endless_episode(self): """Никогда не выбирать случайную позицию для маятника""" enable = self.endless_episode_checkbox.isChecked() self.sim.endless = enable def clear(self): """Очистить графики и поле с информацией об обучении""" self.canvas.clear() self.canvas.draw() self.output_text_field.clear() def paint_scene(self, thetas, omegas, moments, times, running_reward, episode): """Рисовать графики""" self.canvas.clear() self.canvas.theta_plot.plot(times, thetas, 'b') self.canvas.omega_plot.plot(times, omegas, 'g') self.canvas.moment_plot.plot(times, moments, 'r') self.canvas.draw() eps = self.sim.get_eps() self.output_text_field.append( "Episode %d: running reward: %d, random probability: %-10.5g" % (episode, running_reward, eps))