class player_base: r""" An instance of this class controls the exploration of a fractal. :param display: a function which, given a zoom level and possibly its new specification, displays it on the board """ #================================================================================================== def __init__(self, display: Callable[[int, Any], None], **ka): def frames(): self.select(None) self.setrunning(False) yield None while True: yield self.level self.level = -1 self.anim = FuncAnimation( self.board, (lambda i: None if i is None else self.show_precision(display(i))), frames, init_func=(lambda: None), repeat=False, **ka) def setrunning(self, b: bool = None): r"""Sets the running state of the animation to *b* (if :const:`None`, the inverse of current running state).""" if b is None: b = not self.running self.running = b if b: self.anim.resume() else: self.anim.pause() self.show_running(b) def show_running(self, b: bool): r"""Shows the current running state as *b*. This implementation raises an error.""" raise NotImplementedError() def show_precision(self, p: int): r"""Shows the current precision as *p*. This implementation raises an error.""" raise NotImplementedError() def select(self, bounds: Union[Tuple[Tuple[float, float], Tuple[float, float]], None]): r"""Pushes a new level in the animation at the current level plus one. This implementation raises an error.""" raise NotImplementedError()
class BoundedEquationService( DifferentialEquationService[BoundedEquationMetadata], ABC): __animation: Optional[FuncAnimation] = None __is_animation_playing: bool = False def __init__(self, main_figure: Figure): super().__init__(main_figure) def render_current_solution(self): self.clear_figure() self.clear_animation() K, N = self.solution.shape time_domain = np.linspace(0, self.metadata.time, K) space_domain = np.linspace(0, self.metadata.length, N) x, t = np.meshgrid(space_domain, time_domain) ax = self.main_figure.add_subplot(projection='3d') ax.set_xlabel('x [length]') ax.set_ylabel('t [time]') ax.set_zlabel('u(x, t)') surf = ax.plot_surface(x, t, self.solution, cmap=cm.coolwarm, linewidth=0, antialiased=False) self.main_figure.colorbar(surf, shrink=0.5, aspect=5) def generate_animation(self): self.clear_figure() K, N = self.solution.shape ax = self.main_figure.add_subplot() Axes.set_xlim(ax, left=0, right=self.metadata.length) Axes.set_ylim(ax, bottom=np.min(self.solution), top=np.max(self.solution)) ax.set_xlabel("x [length]") ax.set_ylabel("u(x, t)") ax.set_title("Solution: u(x, t)") space_domain = np.linspace(0, self.metadata.length, self.metadata.samples) line, = ax.plot(space_domain, self.solution[0], "-o", markersize=4) time_text = ax.text(0.82, 0.92, '', transform=ax.transAxes) dt = self.metadata.time / K def update_plot(k: int): line.set_ydata(self.solution[k]) time_text.set_text("t = %.3f" % (k * dt)) return line, time_text self.__animation = FuncAnimation(self.main_figure, update_plot, frames=K, blit=True, interval=20) def toggle_animation(self): if not self.__animation: self.generate_animation() self.__is_animation_playing = True elif self.is_animation_playing(): self.__animation.pause() self.__is_animation_playing = False else: self.__animation.resume() self.__is_animation_playing = True def is_animation_playing(self): return self.__is_animation_playing def export_solution(self, table_path: str): K, N = self.solution.shape time_domain = np.linspace(0, self.metadata.time, K) space_domain = np.linspace(0, self.metadata.length, N) workbook = Workbook() worksheet = workbook.active worksheet.cell(1, 2, "x →") for i in range(N): worksheet.cell(1, 3 + i, space_domain[i]) worksheet.write(2, 1, "t ↓") for k in range(K): worksheet.write(3 + k, 1, time_domain[k]) for k in range(K): for i in range(N): worksheet.write(k + 3, i + 3, self.solution[k, i]) workbook.save(table_path) def clear_animation(self): if self.__animation: self.__animation.pause() self.__animation = None self.__is_animation_playing = False self.main_figure.clf()