def add_pose_slider(theta_name, theta, column_index, row_index, x_offset=0.2, y_offset=0.3): pose_index = theta['id'] slider_active = theta['optimize'] slider_color = 'blue' if slider_active else 'gray' slider_background = 'white' if slider_active else 'lightgray' ax_pose = plt.axes([ x_offset + 0.16 * column_index, y_offset - 0.035 * row_index, 0.075, 0.015 ], facecolor=slider_background) slider_initial_val = np.clip(anno['handPose'][pose_index], theta['min'], theta['max']) pose_slider = Slider(ax_pose, theta_name, theta['min'], theta['max'], valinit=slider_initial_val, valstep=0.01, color=slider_color) pose_slider.set_active(slider_active) return pose_index, pose_slider
class CellAutomatonGameGUI(object): """ GUI to control: 1. N = # of creatures 2. P = infection probability 3. K = quarantine parameter 4. L = generation (iteration) from which the quarantine applies 5. animation's speed 6. pause | play | reset buttons """ def __init__(self, game): self.game = game self.N = N self.P = P self.K = K self.L = L # future members self.fig, self.ax = None, None self.animation = None def __set_widgets(self): """ set all sliders and buttons that are in the gui's responsibility """ hcolor = None axcolor = 'white' slider_x_loc = 0.25 slider_y_loc = 0.2 slider_width = 0.6 slider_hight = 0.021 gap = slider_hight + 0.01 # [left, bottom, width, height] # parameters sliders self.n_slider = Slider(plt.axes( [slider_x_loc, slider_y_loc, slider_width, slider_hight], facecolor=axcolor), 'N', 1.0, int(self.game.get_size() / 2), valinit=self.N, valstep=1.0, valfmt='%0.0f') self.p_slider = Slider(plt.axes( [slider_x_loc, slider_y_loc - gap, slider_width, slider_hight], facecolor=axcolor), 'P', 0.0, 1.0, valinit=self.P) self.k_slider_loc = plt.axes( [slider_x_loc, slider_y_loc - 2 * gap, slider_width, slider_hight], facecolor=axcolor) self.k_slider = Slider(self.k_slider_loc, 'K', 1.0, 8.0, valinit=self.K, valstep=1.0, valfmt='%0.0f') self.k_slider_loc.set_visible(False) self.l_slider_loc = self.fig.add_axes( [slider_x_loc, slider_y_loc - 3 * gap, slider_width, slider_hight], facecolor=axcolor) self.l_slider = Slider(self.l_slider_loc, 'L', 0.0, 1000.0, valinit=0, valstep=20.0, valfmt='%0.0f') self.l_slider_loc.set_visible(False) # quarantine option menu self.right_menu_x_loc = 0.025 self.options_button = CheckButtons( plt.axes( [self.right_menu_x_loc, slider_y_loc - 4 * gap, 0.18, 0.15]), ['apply\nquarantine']) self.get_stat_button = None if ALLOW_SAVE_DATA: self.get_stat_button = Button(plt.axes( [self.right_menu_x_loc, slider_y_loc + 15 * gap, 0.12, 0.04]), 'save data', color=axcolor, hovercolor=hcolor) # control animation's speed y_axis_speed = 0.92 plt.text(0.80, y_axis_speed, 'speed: ', transform=self.fig.transFigure) self.speed_box = plt.text(0.88, y_axis_speed, '', transform=self.fig.transFigure) self.speed_up_button = Button(plt.axes( [0.94, y_axis_speed, 0.02, 0.03]), '+', hovercolor=hcolor) self.speed_down_button = Button(plt.axes( [0.96, y_axis_speed, 0.02, 0.03]), '-', hovercolor=hcolor) # control animation buttons self.play_button = Button(plt.axes([0.8, 0.025, 0.1, 0.04]), 'play', color=axcolor, hovercolor=hcolor) self.pause_button = Button(plt.axes([0.69, 0.025, 0.1, 0.04]), 'pause', color=axcolor, hovercolor=hcolor) self.reset_button = Button(plt.axes([0.56, 0.025, 0.12, 0.04]), 'reset', color=axcolor, hovercolor=hcolor) def __set_p(self, e): """ on-click function: change P slider value """ self.P = self.p_slider.val def __set_n(self, e): """ on-click function: change N slider value """ self.N = int(self.n_slider.val) def __set_k(self, e): """ on-click function: change K slider value """ check = self.options_button.get_status()[0] self.k_slider_loc.set_visible(check) self.k_slider.set_active(check) self.K = int(self.k_slider.val) if check else 0 def __set_l(self, e): """ on-click function: change L slider value """ check = self.options_button.get_status()[0] self.l_slider_loc.set_visible(check) self.l_slider.set_active(check) self.L = int(self.l_slider.val) if check else None def __reset_button_on_click(self, e): """ on-click function: pause and reset the game with current parameters """ self.animation.stop() self.game.build(self.N, self.P, self.K, self.L) def set_all(self): """ create gui's visible elements and attach them to event-functions """ self.fig, self.ax = plt.subplots() plt.subplots_adjust(left=0.25, bottom=0.25) self.__set_widgets() self.p_slider.on_changed(self.__set_p) self.n_slider.on_changed(self.__set_n) self.k_slider.on_changed(self.__set_k) self.l_slider.on_changed(self.__set_l) self.options_button.on_clicked(self.__set_l) self.options_button.on_clicked(self.__set_k) self.reset_button.on_clicked(self.__reset_button_on_click) def start(self): """ create all entities and start the animation """ # calculate game's statistics for each time step gs = GameStatistics(self.game) # follow statistics ShowStatistics(gs, self.fig, x=self.right_menu_x_loc) StatAccumulator(gs, self.get_stat_button) if SHOW_ONLINE_GRAPH: OnlineGraph(gs) self.game.build(self.N, self.P, self.K, self.L) self.animation = CellAnimation(self.pause_button, self.play_button, self.speed_up_button, self.speed_down_button, self.speed_box, self.fig, self.ax) self.animation.start(self.game)
ax.set_xlabel('Nombre de Mach') ax.set_ylabel('Consommation spécifique (kg.s-1)') ax.set_xlim(0,6) ax.set_ylim(0,.001) update(1) def switch_mot(val): if (rMot.value_selected=='Statoréacteur'): sPi.set_active(False) sPi.set_val(1) axPi.set_facecolor('gray') update(1) else: sPi.set_active(True) sPi.set_val(5) axPi.set_facecolor('white') update(1) sM.on_changed(update) sAlt.on_changed(update) sPi.on_changed(update) sTt4.on_changed(update) rMod.on_clicked(update) rMot.on_clicked(switch_mot) rGra.on_clicked(switch_mode) sPi.set_active(False) sPi.set_val(1) axPi.set_facecolor('gray') update(1) plt.show()
valmax=100.0, valinit=80, valstep=1) BAR_Y -= BAR_VERTICAL_SPACE * 2 # Observers ########################### CORE ########################### temperature_before_reactor = Slider(plt.axes( [BAR_INIT_X, BAR_Y, BAR_INIT_WIDTH, BAR_HEIGHT], facecolor='lightgoldenrodyellow'), 'Water temperature before core', valmin=0, valmax=730, valstep=1, valfmt='%0.2f C') temperature_before_reactor.set_active(False) BAR_Y -= BAR_VERTICAL_SPACE temperature_in_reactor = Slider(plt.axes( [BAR_INIT_X, BAR_Y, BAR_INIT_WIDTH, BAR_HEIGHT], facecolor='lightgoldenrodyellow'), 'Water temperature in core', valmin=0, valmax=730, valstep=1, valfmt='%0.2f C') temperature_in_reactor.set_active(False) BAR_Y -= BAR_VERTICAL_SPACE temperature_after_reactor = Slider(plt.axes( [BAR_INIT_X, BAR_Y, BAR_INIT_WIDTH, BAR_HEIGHT], facecolor='lightgoldenrodyellow'), 'Water temperature after core',
class guiMenu: fig = None gauss_params = [33, 7] logTextLabels = [] logText = [] axMisc = None axAlgorithm = None axSaveOptions = None axGauss = None axLog = None axRadio = None axLogLabels = None line_gaussian = None ax_window_size = None slider_window_size = None ax_sigma = None slider_sigma = None originalStdOut = None #------------------------------------------------------------------------------ # Class initialization # def __init__(self): self.strTitle = 'Gesture Analysis Configuration - ' + settings.appVersion self.fig = plt.figure() self.fig.canvas.set_window_title(self.strTitle) self.fig.set_size_inches((settings.screen_cx * 0.49) / self.fig.dpi, (settings.screen_cy * 0.465) / self.fig.dpi) self.fig.canvas.mpl_connect('resize_event', self.onresize) self.fig.canvas.mpl_connect('close_event', self.onclose) self.fig.edgecolor = 'blue' self.fig.set_facecolor('0.90') left = 0.03 # the left side of the subplots of the figure right = 0.97 # the right side of the subplots of the figure bottom = 0.04 # the bottom of the subplots of the figure top = 0.92 # the top of the subplots of the figure wspace = 0.3 # the amount of width reserved for blank space between subplots hspace = 0.7 # the amount of height reserved for white space between subplots plt.subplots_adjust(left=left, top=top, right=right, bottom=bottom, wspace=wspace, hspace=hspace) self.axMisc = plt.subplot2grid((6, 4), (0, 0), rowspan=1, colspan=1, aspect='auto', anchor='NW') self.axAlgorithm = plt.subplot2grid((6, 4), (1, 0), rowspan=2, colspan=1, aspect='auto', anchor='NW') self.axSaveOptions = plt.subplot2grid((6, 4), (3, 0), rowspan=3, colspan=1, aspect='equal', anchor='NW') self.axGauss = plt.subplot2grid((6, 4), (0, 1), rowspan=4, colspan=3) self.axLog = plt.subplot2grid((6, 4), (5, 1), rowspan=1, colspan=3, aspect='auto', anchor='NW') # create the various groups of UI controls self.createUIMiscellaneous() self.createUILog() self.createUIAlgorithm() self.createUIGaussianFilterControls() self.createUIMiscellaneousControls() # set settings.tkGuiCanvas for use for modal dialogs try: if (self.fig is not None) and (self.fig.canvas is not None) and ( self.fig.canvas._tkcanvas is not None): settings.tkGuiCanvas = self.fig.canvas._tkcanvas except Exception as e: pass #------------------------------------------------------------------------------ # def get_aspect(self, ax): # Total figure size figW, figH = ax.get_figure().get_size_inches() # Axis size on figure _, _, w, h = ax.get_position().bounds # Ratio of display units disp_ratio = (figH * h) / (figW * w) # Ratio of data units # Negative over negative because of the order of subtraction data_ratio = sub(*ax.get_ylim()) / sub(*ax.get_xlim()) return disp_ratio / data_ratio #------------------------------------------------------------------------------ # def createUIAlgorithm(self): algorithm = settings.application.algorithm.lower() defaultAlgoritmIdx = 0 if (algorithm == 'total'): defaultAlgoritmIdx = 0 elif (algorithm == 'parallel'): defaultAlgoritmIdx = 1 elif (algorithm == 'naive'): defaultAlgoritmIdx = 2 self.axAlgorithm.set_title('Algorithm', x=0, horizontalalignment='left') # create an axis to host to radio buttons. make its aspect ratio # equal so the radiobuttons stay round aspect = self.get_aspect(self.axAlgorithm) rect = [0, 0, 1.0 * aspect, 1.0] ip = InsetPosition(self.axAlgorithm, rect) self.axRadio = plt.axes(rect) self.axRadio.set_axes_locator(ip) self.axRadio.axis('off') self.radioAlgorithm = RadioButtons( self.axRadio, ('Total Energy', 'Parallel Energy', 'Naive (no filter)'), active=defaultAlgoritmIdx) self.radioAlgorithm.on_clicked(self.onClickAlgorithm) #------------------------------------------------------------------------------ # def createUIGaussianFilterControls(self): axcolor = 'lightgoldenrodyellow' rect = [0.82, -0.158, 0.14, 0.07] ax_btnapply = plt.axes(rect) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height ax_btnapply.set_axes_locator(ip) self.btnApply = Button(ax_btnapply, 'Apply') self.btnApply.on_clicked(self.onclickApply) rect = [0.82, -0.245, 0.14, 0.07] ax_btnreset = plt.axes(rect) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height ax_btnreset.set_axes_locator(ip) self.btnReset = Button(ax_btnreset, 'Reset', color='0.950', hovercolor='0.975') self.btnReset.on_clicked(self.onclickReset) rect = [0.1, -0.155, 0.55, 0.04] self.ax_window_size = plt.axes(rect, facecolor=axcolor) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height self.ax_window_size.set_axes_locator(ip) self.slider_window_size = Slider(self.ax_window_size, 'Window Size', 1, (self.gauss_params[0] + 1) * 2 + 1, valinit=self.gauss_params[0], valstep=2) self.slider_window_size.on_changed(self.updateGaussianFilter) rect = [0.1, -0.235, 0.55, 0.04] self.ax_sigma = plt.axes(rect, facecolor=axcolor) ip = InsetPosition(self.axGauss, rect) #posx, posy, width, height self.ax_sigma.set_axes_locator(ip) self.slider_sigma = Slider(self.ax_sigma, 'Sigma', 1, (self.gauss_params[1] + 1) * 2, valinit=self.gauss_params[1], valstep=1) self.slider_sigma.on_changed(self.updateGaussianFilter) self.updateGaussianFilter() #------------------------------------------------------------------------------ # def createUIMiscellaneous(self): self.axMisc.set_title('', x=0, horizontalalignment='left') # removing top and right borders self.axMisc.xaxis.set_visible(False) self.axMisc.yaxis.set_visible(False) # remove ticks self.axSaveOptions.set_xticks([]) self.axSaveOptions.set_yticks([]) # remove ticks self.axAlgorithm.set_xticks([]) self.axAlgorithm.set_yticks([]) bbox = self.axMisc.get_window_extent() self.axMisc.set_xlim(0, bbox.width) self.axMisc.set_ylim(0, bbox.height) #------------------------------------------------------------------------------ # def createUILog(self): self.axLog.set_title('Console Log', x=0, horizontalalignment='left') # removing top and right borders self.axLog.xaxis.set_visible(False) self.axLog.yaxis.set_visible(False) self.resetLogLabels() # redirect console messages to gui's log self.originalStdOut = sys.stdout sys.stdout = CaptureOutput() # ----------------------------------------------------------------------------- # def resetLogLabels(self): cnt = len(self.logTextLabels) for i in range(0, cnt): self.logTextLabels[i].remove() self.logTextLabels = [] bbox = self.axLog.get_window_extent() self.axLog.set_xlim(0, bbox.width) self.axLog.set_ylim(0, bbox.height) aspect = self.get_aspect(self.axLog) rect = [0, 0, 1.0 * aspect, 1.0] ip = InsetPosition(self.axLog, rect) if (self.axLogLabels is None): self.axLogLabels = plt.axes(rect) else: self.axLogLabels.set_position(rect) self.axLogLabels.set_axes_locator(ip) self.axLogLabels.axis('off') aspectLog = 1.0 / self.get_aspect(self.axLog) strText = 'Tyg' tmp, self.logTextHeight = settings.getTextExtent(self.axLog, strText) self.logTextHeight = self.logTextHeight * aspectLog # * self.fig.dpi # pre-create empty log label placeholders self.logTextLabels = [] y = (self.logTextHeight / 4.0) cy = bbox.height idx = len(self.logText) - 1 while (y < cy): str = self.logText[idx] if (idx >= 0) else '' idx = idx - 1 lbl = self.axLogLabels.text( 8.0, y, str, horizontalalignment='left', verticalalignment='bottom', color='dimgray', clip_on=True, transform=self.axLog.transData ) #, bbox={'facecolor':'lightgray', 'alpha':0.7, 'pad':0.0}) self.logTextLabels.append(lbl) y += self.logTextHeight # ----------------------------------------------------------------------------- # def createUIMiscellaneousControls(self): rect = [0.06, 0.30, 0.70, 0.40] ip = InsetPosition(self.axMisc, rect) #posx, posy, width, height ax_btnbrowse = plt.axes(rect) ax_btnbrowse.set_axes_locator(ip) self.btnBrowse = Button(ax_btnbrowse, 'Input File') self.btnBrowse.on_clicked(self.onclickBrowse) self.axSaveOptions.set_title('Output Files', x=0, horizontalalignment='left') x = 0.06 dx = 0.70 # 0.80 dy = 0.10 # 0.17 cy = 0.14 # 0.24 y = 0.80 rect = [x, y, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveJSON = Button(ax_btn, 'JSON') self.btnSaveJSON.on_clicked(self.onclickSaveJSON) rect = [x, y - 1 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveTXT = Button(ax_btn, 'Text') self.btnSaveTXT.on_clicked(self.onclickSaveTXT) rect = [x, y - 2 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveFilterView = Button(ax_btn, 'Filter Graph') self.btnSaveFilterView.on_clicked(self.onclickSaveFilterView) rect = [x, y - 3 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveSkeletonView = Button(ax_btn, '3D Joint Data') self.btnSaveSkeletonView.on_clicked(self.onclickSaveSkeletonView) rect = [x, y - 4 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSaveScoreView = Button(ax_btn, 'Score View') self.btnSaveScoreView.on_clicked(self.onclickSaveScoreView) rect = [x, y - 5 * cy, dx, dy] ip = InsetPosition(self.axSaveOptions, rect) #posx, posy, width, height ax_btn = plt.axes(rect) ax_btn.set_axes_locator(ip) self.btnSavePNG = Button(ax_btn, 'Full Score') self.btnSavePNG.on_clicked(self.onclickSaveImage) #------------------------------------------------------------------------------ # canvas resize event # def onresize(self, event): # plt.tight_layout() # keep tha radio buttons round... if (self.axRadio is not None) and (self.axAlgorithm is not None): aspect = self.get_aspect(self.axAlgorithm) rect = [0, 0, 1.0 * aspect, 1.0] ip = InsetPosition(self.axAlgorithm, rect) self.axRadio.set_axes_locator(ip) self.axRadio.set_position(rect) self.resetLogLabels() # ----------------------------------------------------------------------------- # canvas close event # def onclose(self, event): self.fig = None # if user closes this figure, let the main application know and to exit settings.application.close() # ----------------------------------------------------------------------------- # def updateUIControls(self, algorithm): algorithm = algorithm.lower() fEnable = False if (algorithm == 'naive') else True alpha = 0.2 if (algorithm == 'naive') else 1.0 self.btnApply.set_active(fEnable) self.btnReset.set_active(fEnable) self.btnApply.label.set_alpha(alpha) self.btnReset.label.set_alpha(alpha) fUpdateGaussianPlot = False if (self.gauss_params[0] != self.slider_window_size.val): self.ax_window_size.clear() self.slider_window_size.__init__( self.ax_window_size, 'Window Size', valmin=1, valmax=(self.gauss_params[0] + 1) * 2 + 1, valinit=self.gauss_params[0], valstep=2) self.slider_window_size.on_changed(self.updateGaussianFilter) fUpdateGaussianPlot = True if (self.gauss_params[1] != self.slider_sigma.val): self.ax_sigma.clear() self.slider_sigma.__init__(self.ax_sigma, 'Sigma', valmin=1, valmax=(self.gauss_params[1] + 1) * 2, valinit=self.gauss_params[1], valstep=1) self.slider_sigma.on_changed(self.updateGaussianFilter) fUpdateGaussianPlot = True if (fUpdateGaussianPlot): self.updateGaussianFilter() self.line_gaussian.set_alpha(alpha) self.ax_window_size.patch.set_alpha(alpha) if (self.slider_window_size.poly): self.slider_window_size.poly.set_alpha(alpha) self.slider_window_size.set_active(fEnable) for r in self.slider_window_size.ax.texts: r.set_alpha(alpha) self.ax_sigma.patch.set_alpha(alpha) if (self.slider_sigma.poly): self.slider_sigma.poly.set_alpha(alpha) self.slider_sigma.set_active(fEnable) for r in self.slider_sigma.ax.texts: r.set_alpha(alpha) self.fig.canvas.draw_idle() # ----------------------------------------------------------------------------- # def updateInputName(self): self.fig.canvas.set_window_title( self.strTitle + ' - [' + settings.application.strBeautifiedInputFile + ']') # ----------------------------------------------------------------------------- # def getAlgorithmSelection(self): if (self.radioAlgorithm.value_selected == 'Total Energy'): return 'Total' elif (self.radioAlgorithm.value_selected == 'Parallel Energy'): return 'Parallel' return 'Naive' # ----------------------------------------------------------------------------- # def onClickAlgorithm(self, label): algorithm = self.getAlgorithmSelection() if (settings.application.labanotation is not None): self.gauss_params = settings.application.labanotation.getGaussianParameters( algorithm) self.updateUIControls(algorithm) settings.application.applyAlgoritm(algorithm) #------------------------------------------------------------------------------ # updateGaussianFilter() has an unused parameter, though needs it because the # sliders use this function as their update callback... def updateGaussianFilter(self, val=0): # remove current gaussian lines if (self.line_gaussian is not None): self.line_gaussian.remove() del self.line_gaussian self.line_gaussian = None gauss_params = (int(self.slider_window_size.val), int(self.slider_sigma.val)) self._t = np.arange(-gauss_params[0] / 2.0 + 0.5, gauss_params[0] / 2.0 + 0.5, 1.0) s = wf.gaussFilter(gauss_params[0], gauss_params[1]) self.line_gaussian, = self.axGauss.plot(self._t, s, marker="o", linestyle='-', color='red', lw=1) # for i, txt in enumerate(s): # self.axGauss.annotate("{:0.2f}".format(txt), (self._t[i], s[i])) wnd = int(gauss_params[0] / 2) + 1 self.axGauss.set_xlim(-wnd, wnd) self.axGauss.set_ylim(0, 0.42) # np.max(s)) self.fig.canvas.draw_idle() #------------------------------------------------------------------------------ # def onclickApply(self, event): algorithm = self.getAlgorithmSelection() self.gauss_params = (int(self.slider_window_size.val), int(self.slider_sigma.val)) if (settings.application.labanotation is not None): settings.application.labanotation.setGaussianParameters( algorithm, self.gauss_params) settings.application.applyAlgoritm(algorithm) #------------------------------------------------------------------------------ # def onclickSaveJSON(self, event): settings.application.saveJSON() #------------------------------------------------------------------------------ # def onclickSaveTXT(self, event): settings.application.saveTXT() #------------------------------------------------------------------------------ # def onclickSaveImage(self, event): settings.application.saveImage() #------------------------------------------------------------------------------ # def onclickSaveFilterView(self, event): settings.application.saveFilterView() #------------------------------------------------------------------------------ # def onclickSaveSkeletonView(self, event): settings.application.saveSkeletonView() #------------------------------------------------------------------------------ # def onclickSaveScoreView(self, event): settings.application.saveScoreView() #------------------------------------------------------------------------------ # def onclickReset(self, event): self.slider_window_size.reset() self.slider_sigma.reset() #------------------------------------------------------------------------------ # def onclickBrowse(self, event): file = self.selectInputFile() if (file is None): return settings.application.openAndProcessInputfile(file) #------------------------------------------------------------------------------ # def selectInputFile(self): fTyp = [("Kinect Joint Data File", "*.csv")] splitInput = os.path.split( os.path.abspath(settings.application.inputFilePath)) options = {} options['filetypes'] = fTyp options['initialdir'] = splitInput[0].replace('/', os.sep) if (settings.tkGuiCanvas is not None): options['parent'] = settings.tkGuiCanvas file = tkFileDialog.askopenfilename(**options) if not file: return None return file #------------------------------------------------------------------------------ # def logMessage(self, str, ioRedirect=False): # also write message to console if (self.originalStdOut is not None): extra = "\r\n" if (ioRedirect is False) else "" self.originalStdOut.write(str + extra) self.logText.append(str) cnt = len(self.logTextLabels) if (cnt > 0): for i in range(cnt - 1, 0, -1): self.logTextLabels[i].set_text( self.logTextLabels[i - 1].get_text()) self.logTextLabels[0].set_text(str) self.fig.canvas.draw_idle()
class GUI: def __init__(self, _is_progress_bar=True): self.fig = plt.figure(figsize=(10, 8), dpi=80) self.ax = self.fig.add_subplot(111, aspect='equal') self.__init_axes() def handle_close(evt): print('Execution terminated') plt.close('all') sys.exit() self.fig.canvas.mpl_connect('close_event', handle_close) widget_color = 'palegoldenrod' if _is_progress_bar: self.fig.subplots_adjust(bottom=0.2) self.progress_slider_ax = self.fig.add_axes( [0.15, 0.08, 0.75, 0.04], facecolor=widget_color) self.progress_slider = Slider(self.progress_slider_ax, 'Progress', 0, 100, valinit=0, dragging=False) self.progress_slider.set_active(False) self.next_button_ax = self.fig.add_axes([0.8, 0.01, 0.1, 0.04]) self.next_button = Button(self.next_button_ax, 'Next', color=widget_color, hovercolor='lightgray') self.next = False def next_button_callback(mouse_event): self.next = True self.next_button.on_clicked(next_button_callback) def __init_axes(self): x_ticks = range(-5, 10) y_ticks = range(-7, 8) self.ax.set_xticks(x_ticks) self.ax.set_yticks(y_ticks) self.ax.set_xlim([-5, 9]) self.ax.set_ylim([-7, 7]) self.ax.grid(which='both') def visualize(self, edges, new_edges=[], possible_values_for_p1=[]): self.ax.cla() self.__init_axes() for seg in edges: a, b = seg xa, ya = a xb, yb = b self.ax.plot((xa, xb), (ya, yb), color='blue') for seg in new_edges: a, b = seg xa, ya = a xb, yb = b self.ax.plot((xa, xb), (ya, yb), linewidth=3, color='orange') for pt in possible_values_for_p1: x, y = pt self.ax.plot([x], [y], marker='o', markersize=10, color='purple') plt.pause(0.001) def set_title(self, title): self.fig.canvas.set_window_title(title)
class GUIInterface: def __init__(self): # based on the answer https://stackoverflow.com/a/43382060/3350732 # of user buvinj https://stackoverflow.com/users/3220983/buvinj # from https://stackoverflow.com/questions/17280637/tkinter-messagebox-without-window # self.root will store the root of tKinter which is used for message boxes, # but we only use matplotlib for the main GUI window # GUI INIT self.waiting_time = 1 # initially the waiting time between plots is 1s self.fig = plt.figure(figsize=(10, 8), dpi=80) self.fig.canvas.set_window_title( 'OPTIMAL DEGREE-THREE SPANNERS OF THE SQUARE LATTICE') def handle_close(evt): print('Execution terminated') plt.close('all') sys.exit() self.fig.canvas.mpl_connect('close_event', handle_close) self.ax = self.fig.add_subplot(111, aspect='equal') self.__init_axes() self.fig.subplots_adjust(left=0.2, bottom=0.2) widget_color = 'palegoldenrod' self.progress_slider_ax = self.fig.add_axes([0.15, 0.08, 0.75, 0.04], facecolor=widget_color) self.progress_slider = Slider(self.progress_slider_ax, 'Progress', 0, 100, valinit=0, dragging=False) self.progress_slider.set_active(False) self.in_pause = False self.pause_button_ax = self.fig.add_axes([0.8, 0.01, 0.1, 0.04]) self.pause_button = Button(self.pause_button_ax, 'Pause', color=widget_color, hovercolor='lightgray') self.pause_button.resume_label = self.pause_button_ax.text( 0.5, 0.5, 'Resume', verticalalignment='center', horizontalalignment='center') self.pause_button.resume_label.set_visible(False) def pause_button_callback(mouse_event): if self.in_pause: self.in_pause = False self.pause_button.label.set_visible(True) self.pause_button.resume_label.set_visible(False) else: self.in_pause = True self.pause_button.label.set_visible(False) self.pause_button.resume_label.set_visible(True) self.pause_button.on_clicked(pause_button_callback) self.waiting_time_radios_ax = self.fig.add_axes( [0.025, 0.5, 0.15, 0.15], facecolor=widget_color) self.waiting_time_radios = RadioButtons( self.waiting_time_radios_ax, ('plotting time', '0.3s', '1s', '3s'), active=1) def waiting_time_callback(label): if label == 'plotting time': self.waiting_time = 0.001 else: self.waiting_time = float(label[:-1]) self.fig.canvas.draw_idle() self.waiting_time_radios.on_clicked(waiting_time_callback) self.fig.canvas.draw_idle() plt.pause(self.waiting_time) def notify_start(self, edges, forbidden_edges, to_prove): self.current_tot = to_prove.tot self.progress_slider.set_val(0) self.is_uv_constraint = (to_prove.u is not None and to_prove.v is not None) self.shortcut = None self.pattern = None self.unique_path = None self.impossible_to_join = None print('We now consider the proof of', to_prove.name) print('Known lemmas so far:', str([lemma.name for lemma in to_prove.known_lemmas])) def notify_end(self, to_prove): print('Finished the proof of', to_prove.name) def notify_finished(self): print('The proof is complete!') def notify_shortcut(self, edges, forbidden_edges, shortcut): self.shortcut = shortcut self.__visualize(edges, forbidden_edges) self.shortcut = None def notify_pattern(self, edges, forbidden_edges, pattern): self.pattern = pattern self.__visualize(edges, forbidden_edges) self.pattern = None def notify_unique_path(self, edges, forbidden_edges, unique_path): self.unique_path = unique_path self.__visualize(edges, forbidden_edges) self.unique_path = None def notify_impossible_to_join(self, edges, forbidden_edges, p, q): self.impossible_to_join = (p, q) self.__visualize(edges, forbidden_edges) self.impossible_to_join = None def notify_branch(self, edges, forbidden_edges, tot): self.__visualize(edges, forbidden_edges) self.progress_slider.set_val(100 * tot / self.current_tot) def __curly_path(self, a, b, col): # modified from the answer https://stackoverflow.com/a/50918519/3350732 # of user hayk-hakobyan https://stackoverflow.com/users/4888158/hayk-hakobyan # from https://stackoverflow.com/questions/45365158/matplotlib-wavy-arrow xa, ya = a xb, yb = b dist = np.hypot(xb - xa, yb - ya) theta = np.arctan2(yb - ya, xb - xa) n = 3 * round(dist) x = np.linspace(0, dist, 200) y = 0.2 * np.sin(2 * np.pi * x * n / dist) for i in range(200): old_x, old_y = x[i], y[i] x[i] = np.cos(theta) * old_x - np.sin(theta) * old_y y[i] = np.sin(theta) * old_x + np.cos(theta) * old_y self.ax.plot(x + xa, y + ya, linewidth=3, color=col) def __init_axes(self): x_ticks = range(-5, 7) y_ticks = range(-5, 7) self.ax.set_xticks(x_ticks) self.ax.set_yticks(y_ticks) self.ax.set_xlim([-5, 6]) self.ax.set_ylim([-5, 6]) self.ax.grid(which='both') def __visualize(self, edges, forbidden_edges): while self.in_pause: self.fig.canvas.start_event_loop(0.01) self.ax.cla() self.__init_axes() for seg in edges: a, b = seg xa, ya = a xb, yb = b self.ax.plot((xa, xb), (ya, yb), color='blue') for seg in forbidden_edges: a, b = seg xa, ya = a xb, yb = b self.ax.plot((xa, xb), (ya, yb), color='lightsalmon') if self.shortcut is not None: ls_x = [] ls_y = [] for pt in self.shortcut: x, y = pt ls_x.append(x) ls_y.append(y) len_shortcut = len(self.shortcut) for i in range(len_shortcut - 1): a, b = self.shortcut[i], self.shortcut[i + 1] if (a, b) in edges: xa, ya = a xb, yb = b self.ax.plot((xa, xb), (ya, yb), linewidth=4, linestyle='--', color='magenta') else: self.__curly_path(a, b, 'magenta') if self.unique_path is not None: ls_x = [] ls_y = [] for pt in self.unique_path: x, y = pt ls_x.append(x) ls_y.append(y) self.ax.plot(ls_x, ls_y, linestyle='--', linewidth=4, color='limegreen') if self.pattern is not None: for seg in self.pattern: a, b = seg xa, ya = a xb, yb = b self.ax.plot((xa, xb), (ya, yb), linewidth=5, color='darkviolet') if self.impossible_to_join is not None: a, b = self.impossible_to_join self.__curly_path(a, b, 'red') if self.is_uv_constraint: self.ax.plot([0], [0], marker='o', markersize=8, color='magenta') self.ax.plot([1], [2], marker='o', markersize=8, color='magenta') self.fig.canvas.draw_idle() self.fig.canvas.start_event_loop(self.waiting_time)