def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) # Set up a default grid spacing self.set_theta_grid(np.pi/4.) self.set_phi_grid(np.pi/2.) self.set_phi_grid_ends(np.pi/8.) # Turn off minor ticking altogether self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) # Do not display ticks self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') # The limits on this projection are fixed -- they are not to # be changed by the user. This makes the math in the # transformation itself easier, and since this is a toy # example, the easier, the better. Axes.set_xlim(self, 0, np.pi) Axes.set_ylim(self, 0, 2 * np.pi)
def cla(self): """Identical to Axes.cla (This docstring is overwritten).""" Axes.cla(self) # Set grid defaults... self.set_longitude_grid(10) self.set_latitude_grid(10) self.set_longitude_grid_ends(80) # Hide all ticks and tick labels for the "native" lon and lat axes self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.xaxis.set_tick_params(label1On=False) self.yaxis.set_tick_params(label1On=False) # Set the grid on or off based on the rc params. self.grid(mpl.rcParams['axes.grid']) # Set the default limits (so that the "native" ticklabels will be # correct if they're turned back on)... Axes.set_xlim(self, -self.horizon, self.horizon) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0) # Set up the azimuth ticks. self._polar.set_theta_offset(np.radians(self.rotation + 90)) self._polar.set_theta_direction(-1) self._polar.grid(False) self._polar.set_rticks([])
def cla(self): # Disconnect the various events we set. for cid in self.cids: self.figure.canvas.mpl_disconnect(cid) self.cids = [] Axes.cla(self) self.grid(rcParams['axes3d.grid'])
def cla(self): Axes.cla(self) self.title.set_y(1.05) self.xaxis.set_major_formatter(self.ThetaFormatter()) self.xaxis.isDefault_majfmt = True start = self.spines.get('start', None) if start: start.set_visible(False) end = self.spines.get('end', None) if end: end.set_visible(False) self.set_xlim(0.0, 2 * np.pi) self.xaxis.set_major_locator( self.ThetaLocator(self.xaxis.get_major_locator())) self.grid(rcParams['polaraxes.grid']) self.xaxis.set_ticks_position('none') inner = self.spines.get('inner', None) if inner: inner.set_visible(False) self.yaxis.set_ticks_position('none') # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.yaxis.set_tick_params(label1On=True) self.yaxis.set_major_locator( self.RadialLocator(self.yaxis.get_major_locator(), self)) self.set_rorigin(None) self.set_theta_offset(self._default_theta_offset) self.set_theta_direction(self._default_theta_direction)
def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) # Turn off minor ticking altogether self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_major_locator(MaxNLocator(5, prune='both')) self.yaxis.set_major_locator(MaxNLocator(5, prune='both')) # Do not display ticks -- we only want gridlines and text self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.set_center(None, None) # FIXME: probabaly want to override autoscale_view # to properly handle wrapping introduced by margin # and properlty wrap data. # It doesn't make sense to have xwidth > 360. self._tight = True
def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) self.patch.set_transform(self.transClip) # Turn off minor ticking altogether self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_major_locator(MaxNLocator(5, prune='both')) self.yaxis.set_major_locator(MaxNLocator(5, prune='both')) # Do not display ticks -- we only want gridlines and text self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.set_center(None, None) # FIXME: probabaly want to override autoscale_view # to properly handle wrapping introduced by margin # and properlty wrap data. # It doesn't make sense to have xwidth > 360. self._tight = True self._xmargin = 0 self._ymargin = 0
def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) # Set up a default grid spacing self.set_longitude_grid(60) self.set_latitude_grid(30) self.set_longitude_grid_ends(90) # Turn off minor ticking altogether self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) # Do not display ticks -- we only want gridlines and text self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') for tx in self.xaxis.get_major_ticks(): tx.label.set_fontsize(10) for ty in self.yaxis.get_major_ticks(): ty.label.set_fontsize(15) # The limits on this projection are fixed -- they are not to # be changed by the user. This makes the math in the # transformation itself easier, and since this is a toy # example, the easier, the better. Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) # Set up a default grid spacing self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) # Turn off minor ticking altogether self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) # Do not display ticks -- we only want gridlines and text self.xaxis.set_ticks_position("none") self.yaxis.set_ticks_position("none") # The limits on this projection are fixed -- they are not to # be changed by the user. This makes the math in the # transformation itself easier, and since this is a toy # example, the easier, the better. Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): """Identical to Axes.cla (This docstring is overwritten).""" Axes.cla(self) # Set grid defaults... self.set_longitude_grid(10) self.set_latitude_grid(10) self.set_longitude_grid_ends(80) # Hide all ticks and tick labels for the "native" lon and lat axes self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.xaxis.set_tick_params(label1On=False) self.yaxis.set_tick_params(label1On=False) # Set the grid on or off based on the rc params. self.grid(mpl.rcParams['axes.grid']) # Set the default limits (so that the "native" ticklabels will be # correct if they're turned back on)... Axes.set_xlim(self, -2 * self.horizon, 2 * self.horizon) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0) # Set up the azimuth ticks. self._polar.set_theta_offset(np.radians(self.rotation + 90)) self._polar.set_theta_direction(-1) self._polar.grid(False) self._polar.set_rticks([])
def cla(self): """Provide reasonable defaults for the axes. """ # Call the base class. Axes.cla(self) self.grid(True) # Only the x-axis is shown, but there are 3 axes once all of the # projections are included. self.yaxis.set_visible(False) # Adjust the number of ticks shown. #self.set_xticks(np.linspace(0, self.viewLim.x1, 5)) self.set_xticks(np.linspace(0, self.total, 5)) # Turn off minor ticking altogether. self.xaxis.set_minor_locator(NullLocator()) # Place the title a little higher than normal. self.title.set_y(1.02) # Modify the padding between the tick labels and the axis labels. self.xaxis.labelpad = 10 # In display units # Spacing from the vertices (tips) to the tip labels (in data coords, as # a fraction of self.total) self.tipoffset = 0.14
def cla(self): """ Override to set up some reasonable defaults. """ Axes.cla(self) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_major_locator(NullLocator()) self.yaxis.set_major_locator(NullLocator())
def cla(self): # Don't forget to call the base class Axes.cla(self) self._fancy_majorarcs = [] self._normbox = None self._scale = self._get_key("axes.scale") self._current_zorder = self._get_key("plot.zorder") self.xaxis.set_major_locator(self.RealMaxNLocator(self, self._get_key("grid.major.xmaxn"))) self.yaxis.set_major_locator(self.ImagMaxNLocator(self, self._get_key("grid.major.ymaxn"))) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') Axes.set_xlim(self, 0, self._ax_lim_x * self._scale) Axes.set_ylim(self, -self._ax_lim_y * self._scale, self._ax_lim_y * self._scale) for label in self.get_xticklabels(): label.set_verticalalignment('center') label.set_horizontalalignment('center') label.set_rotation(self._get_key("axes.xlabel.rotation")) label.set_bbox(self._get_key("axes.xlabel.fancybox")) self.add_artist(label) # if not readded, labels are drawn behind grid for tick, loc in zip(self.yaxis.get_major_ticks(), self.yaxis.get_majorticklocs()): # workaround for fixing to small infinity symbol if abs(loc) > self._near_inf * self._scale: tick.label.set_size(tick.label.get_size() + self._get_key("symbol.infinity.correction")) tick.label.set_verticalalignment('center') x = np.real(self._moebius_z(loc * 1j)) if x < -0.1: tick.label.set_horizontalalignment('right') elif x > 0.1: tick.label.set_horizontalalignment('left') else: tick.label.set_horizontalalignment('center') self.yaxis.set_major_formatter(self.ImagFormatter(self)) self.xaxis.set_major_formatter(self.RealFormatter(self)) norm = self._get_key("axes.norm") if norm is not None: x, y = split_complex(self._moebius_inv_z(-1 - 1j)) self._normbox = self.text(x, y, "Norm: %d\u2126" % norm) self._normbox.set_verticalalignment("center") px = self._get_key("ytick.major.pad") py = px + 0.5 * self._normbox.get_size() self._normbox.set_transform(self._yaxis_correction + \ Affine2D().translate(-px, -py)) self.grid(b=self._get_key("grid.major.enable"))
def cla(self): Axes.cla(self) self.title.set_y(1.05) self.xaxis.set_major_formatter(self.ThetaFormatter()) angles = npy.arange(0.0, 360.0, 45.0) self.set_thetagrids(angles) self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) self.grid(rcParams['polaraxes.grid']) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none')
def cla(self): Axes.cla(self) self.xaxis.set_major_formatter(self.ThetaFormatter()) angles = npy.arange(0.0, 360.0, 45.0) self.set_thetagrids(angles) self.yaxis.set_major_locator( self.RadialLocator(self.yaxis.get_major_locator())) self.grid(rcParams['polaraxes.grid']) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none')
def cla(self): """ Override to set up sensible defaults """ Axes.cla(self) self.set_longitude_grid(45) self.set_latitude_grid(20) self.set_xlim([-180, 180]) self.set_ylim([-90, 90]) # Do not display ticks -- we only want gridlines and text self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none')
def cla(self): Axes.cla(self) self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.grid(rcParams['axes.grid']) Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): Axes.cla(self) self.title.set_y(1.05) self.xaxis.set_major_formatter(self.ThetaFormatter()) angles = np.arange(0.0, 360.0, 45.0) self.set_thetagrids(angles) self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) self.grid(rcParams["polaraxes.grid"]) self.xaxis.set_ticks_position("none") self.yaxis.set_ticks_position("none") self.yaxis.set_tick_params(label1On=True)
def cla(self): Axes.cla(self) self.title.set_y(1.05) self.xaxis.set_major_formatter(self.ThetaFormatter()) self.xaxis.isDefault_majfmt = True angles = np.arange(0.0, 360.0, 45.0) self.set_thetagrids(angles) self.yaxis.set_major_locator( self.RadialLocator(self.yaxis.get_major_locator())) self.grid(rcParams['polaraxes.grid']) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.yaxis.set_tick_params(label1On=True)
def cla(self): Axes.cla(self) # Disables the log-formatting that comes with semilogy self.yaxis.set_major_formatter(ScalarFormatter()) self.yaxis.set_major_locator(MultipleLocator(100)) if not self.yaxis_inverted(): self.invert_yaxis() # Try to make sane default temperature plotting self.xaxis.set_major_locator(MultipleLocator(5)) self.xaxis.set_major_formatter(ScalarFormatter()) self.set_xlim(*self.default_xlim) self.set_ylim(*self.default_ylim) self._mixing_lines_plotted = [] self._dry_adiabats_plotted = [] self._moist_adiabats_plotted = []
def cla(self): Axes.cla(self) self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.yaxis.set_tick_params(label1On=True) # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.grid(rcParams['axes.grid']) Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): """ Initialize the Axes object to reasonable defaults. """ Axes.cla(self) self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') # self.grid(rcParams['axes.grid']) Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): """ Initialize the Axes object to reasonable defaults. """ Axes.cla(self) self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') # self.grid(rcParams['axes.grid']) Axes.set_xlim(self, -npy.pi, npy.pi) Axes.set_ylim(self, -npy.pi / 2.0, npy.pi / 2.0)
def cla(self): Axes.cla(self) self.set_longitude_grid(60) self.set_latitude_grid(30) self.set_longitude_grid_ends(90) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.yaxis.set_tick_params(label1On=True) # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.grid(rcParams['axes.grid']) Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): Axes.cla(self) self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.yaxis.set_tick_params(label1On=True) # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.grid(rcParams['axes.grid']) lim = self._limit Axes.set_xlim(self, -lim * 2., lim * 2.) Axes.set_ylim(self, -lim, lim)
def cla(self): Axes.cla(self) self.title.set_y(1.05) # Format radians as degrees self.xaxis.set_major_formatter(self.ThetaFormatter()) # Nice theta spacing... self.set_thetagrids(npy.arange(0.0, 360.0, 45.0)) # Axis line for the r axis self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) # Grid lines self.grid(rcParams['polaraxes.grid']) # remove x & y ticks self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none')
def cla(self): Axes.cla(self) self.set_longitude_grid(30) self.set_latitude_grid(10) self.set_longitude_grid_ends(89) self.set_latitude_grid_ends(89) self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') # self.yaxis.set_tick_params(label1On=True) # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.grid(rcParams['axes.grid']) Axes.set_xlim(self, -180, 179.999) # Axes.set_ylim(self, -90, 90) Axes.set_ylim(self, -80, 80)
def cla(self): Axes.cla(self) self.title.set_y(1.05) self.xaxis.set_major_formatter(self.ThetaFormatter()) self.xaxis.isDefault_majfmt = True angles = np.arange(0.0, 360.0, 45.0) self.set_thetagrids(angles) self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) self.grid(rcParams['polaraxes.grid']) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.yaxis.set_tick_params(label1On=True) # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.set_theta_offset(self._default_theta_offset) self.set_theta_direction(self._default_theta_direction)
def cla(self): Axes.cla(self) self.title.set_y(1.05) self.xaxis.set_major_formatter(self.ThetaFormatter()) self.xaxis.isDefault_majfmt = True angles = np.arange(0.0, 360.0, 45.0) self.set_thetagrids(angles) self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) self.grid(rcParams['polaraxes.grid']) self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') self.yaxis.set_tick_params(label1On=True) # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? self.set_theta_offset(0) self.set_theta_direction(1)
def display_plot(ax: Axes, data: masked_array, lower_line: int, upper_line: int) -> None: """ Display an interactive plot. Mark lower and upper limit of magnitude by clicking on the plot. Parameters ---------- ax : AxesSubplot An axes subplot. data : MaskedArray The (n, 3)-shaped array with data. lower_line : float A bottom cut-off for magnitude. upper_line : float An upper cut-off for magnitude. """ ax.cla() _draw_plot(ax, data, lower_line, upper_line, 4) _ = Cursor(ax, useblit=True, color="gray", linewidth=0.5) fig.canvas.mpl_connect("button_press_event", _onclick) plt.show()
def cla(self): Axes.cla(self) self.title.set_y(1.05) start = self.spines.get('start', None) if start: start.set_visible(False) end = self.spines.get('end', None) if end: end.set_visible(False) self.set_xlim(0.0, 2 * np.pi) self.grid(rcParams['polaraxes.grid']) inner = self.spines.get('inner', None) if inner: inner.set_visible(False) self.set_rorigin(None) self.set_theta_offset(self._default_theta_offset) self.set_theta_direction(self._default_theta_direction)
def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) x_min = 0 y_min = 0 x_max = 1 y_max = 1 x_spacing = 0.1 y_spacing = 0.1 self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('bottom') self.yaxis.set_ticks_position('left') Axes.set_xlim(self, x_min, x_max) Axes.set_ylim(self, y_min, y_max) self.xaxis.set_ticks(np.arange(x_min, x_max + x_spacing, x_spacing)) self.yaxis.set_ticks(np.arange(y_min, y_max + y_spacing, y_spacing))
def cla(self): """ Override to set up some reasonable defaults. """ # Don't forget to call the base class Axes.cla(self) x_min = 0 y_min = 0 x_max = 1 y_max = 1 x_spacing = 0.1 y_spacing = 0.1 self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) self.xaxis.set_ticks_position('bottom') self.yaxis.set_ticks_position('left') Axes.set_xlim(self, x_min, x_max) Axes.set_ylim(self, y_min, y_max) self.xaxis.set_ticks(np.arange(x_min, x_max+x_spacing, x_spacing)) self.yaxis.set_ticks(np.arange(y_min, y_max+y_spacing, y_spacing))
def cla(self): #tidak menentukan hasil langsung Axes.cla(self) #menentukan jarak pada pengaturan umum self.set_longitude_grid(30) self.set_latitude_grid(15) self.set_longitude_grid_ends(75) #menonaktifkan tempat yang tidak sesuai self.xaxis.set_minor_locator(NullLocator()) self.yaxis.set_minor_locator(NullLocator()) #hanya menampilkan garis dan teks self.xaxis.set_ticks_position('none') self.yaxis.set_ticks_position('none') #batasan pada projek ini sudah ditentukan dan tak bisa dirubah pengguna #dimana akan meringankan perhitungan dalam bertransformasi dengan sendirinya #lebih mudah dan bahkan lebih baik Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0)
def cla(self): for cid in self.cids: self.figure.canvas.mpl_disconnect(cid) self.cids = [] Axes.cla(self) self.grid(rcParams['axes3d.grid'])
class Projector(object): dpi = 100 # make sure that figures can be displayed pixel-precise css = ''' body { margin:0px; background-color: #FFFFFF; } .panel { background-color: #000000; overflow: hidden; } .bk.frame { background-color: #FFFFFF; color: #FFFFFF; } .bk.legend { background-color: #16425B; color: #CCCCCC; } .bk.hot { background-color: #2896A5; color: #CCCCCC; } .bk.profile { background-color: #40C1C7; color: #CCCCCC; } .bk.colorbar { background-color: #2896A5; color: #CCCCCC; ''' def __init__(self, calibprojector: str = None, use_panel: bool = True, p_width=1280, p_height=800, show_colorbar: bool = False, position_colorbar: str = "vertical", show_legend: bool = False, show_hot: bool = False, show_profile: bool = False, ): """ Args: calibprojector: use_panel: Automatically display p_width: x native resolution of the projector p_height: y native resolution of the projector show_colorbar: position_colorbar: "vertical" or "horizontal" show_legend: show_hot: show_profile """ self.version = '2.2.p' self.ax = None self.figure = None self.json_filename = calibprojector # flags self.enable_legend = show_legend self.enable_hot = show_hot self.enable_colorbar = show_colorbar self.pos_colorbar = position_colorbar self._ratio = 10 self.enable_profile = show_profile if calibprojector is None: self.p_width = p_width self.p_height = p_height self.p_frame_top = 50 self.p_frame_left = 50 self.p_frame_width = 700 self.p_frame_height = 500 # Colorbar self.col_top = 0 self.col_left = 0 if self.pos_colorbar == "vertical" else self.p_frame_left self.col_width = self.p_frame_width if self.pos_colorbar == "horizontal" \ else round(self.p_frame_width / self._ratio) self.col_height = self.p_frame_height if self.pos_colorbar == "vertical" \ else round(self.p_frame_height / self._ratio) self.leg_width = round(self.p_frame_width/4) self.leg_height = round(self.p_frame_width/3) self.leg_top = 0 self.leg_left = 0 else: self.load_json(calibprojector) self._size_label_cbar = 15 self._label = None # panel components (panes) self.panel = None self.frame = None self.legend = None self.hot = None self.profile = None self.colorbar = None self.sidebar = None # This is to solve issue #3. Give 0.01 ms to each Text from ax.arists to be plotted self._target_time = 0.00 self._paused_time = None self.create_panel() if use_panel is True: self.start_server() @property def _dim_label_ax(self): return [0, 0, 2, 0.1] if self.pos_colorbar == "horizontal" else [0, 0, 0.1, 2] def create_panel(self): """ Initializes the matplotlib figure and empty axes according to projector calibration. The figure can be accessed by its attribute. It will be 'deactivated' to prevent random apperance in notebooks. """ pn.extension(raw_css=[self.css]) # Create a panel object and serve it within an external bokeh browser that will be opened in a separate window # In this special case, a "tight" layout would actually add again white space to the plt canvas, # which was already cropped by specifying limits to the axis self.figure = Figure(figsize=(self.p_frame_width / self.dpi, self.p_frame_height / self.dpi), dpi=self.dpi) self.ax = Axes(self.figure, [0., 0., 1., 1.]) self.figure.add_axes(self.ax) self.ax.set_axis_off() self.ax.get_xaxis().set_visible(False) self.ax.get_yaxis().set_visible(False) self.frame = pn.pane.Matplotlib(self.figure, width=self.p_frame_width, height=self.p_frame_height, margin=[self.p_frame_top, 0, 0, self.p_frame_left], tight=False, dpi=self.dpi, css_classes=['frame'] ) plt.close(self.figure) # close figure to prevent inline display if self.enable_colorbar: self.create_colorbar() if self.enable_legend: self.create_legend() if self.enable_hot: self.create_hot() if self.enable_profile: self.create_profile() # Combine panel and deploy bokeh server if self.pos_colorbar == "vertical": self.sidebar = pn.Column(self.colorbar, self.legend, self.hot, self.profile, margin=[self.p_frame_top, 0, 0, 0], ) self.panel = pn.Row(pn.Column(self.frame, None), self.sidebar, width=self.p_width, height=self.p_height, sizing_mode='fixed', css_classes=['panel'] ) elif self.pos_colorbar == "horizontal": self.sidebar = pn.Column(self.legend, self.hot, self.profile, margin=[self.p_frame_top, 0, 0, 0], ) self.panel = pn.Row(pn.Column(self.frame, self.colorbar), self.sidebar, width=self.p_width, height=self.p_height, sizing_mode='fixed', css_classes=['panel'] ) else: raise AttributeError return True def create_colorbar(self): empty_fig_bg_cb = Figure() self.colorbar = pn.pane.Matplotlib(empty_fig_bg_cb, width= self.col_width, height= self.col_height, margin=[self.col_top, 0, 0, self.col_left], dpi=self.dpi*2, css_classes=['colorbar'], tight=True) def create_legend(self): empty_fig_bg_ld = Figure() self.legend = pn.pane.Matplotlib(empty_fig_bg_ld, width=self.leg_width, height=self.leg_height, margin=[self.leg_top, 0, 0, self.leg_left], dpi=self.dpi*2, css_classes=['legend'], tight=True) def create_hot(self): self.hot = pn.Column("### Hot area", width=100, height=100, margin=[0, 0, 0, 0], css_classes=['hot'] ) def create_profile(self): self.profile = pn.Column("### Profile", width=100, height=100, margin=[0, 0, 0, 0], css_classes=['profile'] ) def set_colorbar(self, vmin: float, vmax: float, cmap="viridis", norm=None, label: str = None): """ Create a colorbar and display the figure in the colorbar widget Args: vmin: Minimun value of the colorbar vmax: Maximum value of the colorbar cmap: Colormap of the colorbar norm: (optionl) Normalization, in case that not, this is internally managed label: Text to display as label in the colorbar Returns: """ if self.colorbar is not None: if isinstance(cmap, str): cmap = plt.get_cmap(cmap) label = label if label is not None else self._label cb = Figure() ax = Axes(cb, self._dim_label_ax) cb.add_axes(ax) norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax) if norm is None else norm cb1 = matplotlib.colorbar.ColorbarBase(ax, cmap=cmap, norm=norm, orientation=self.pos_colorbar) cb1.set_label(label, size=self._size_label_cbar) if label is not None else None cb1.ax.tick_params(labelsize=self._size_label_cbar) self.colorbar.object = cb self.colorbar.param.trigger("object") def set_legend(self, handles=None, labels=None, *args): """ Create a legend with the information of frame with the ax.get_legend_handles_labels(). External handles and labels can be used Returns: """ if self.legend is not None: ld = Figure() if handles is None and labels is None: if args == (): ld.legend(*self.ax.get_legend_handles_labels()) else: ld.legend(*args) else: ld.legend(labels=labels, handles=handles ) self.legend.object = ld self.legend.param.trigger("object") def write_text(self, text: str = "cgre-aachen / open_AR_Sandbox"): """ Display a custom text to be displayed in the middle of the sandbox Args: text: message to display Returns: """ self.ax.texts = [] x = (self.ax.get_xlim()[1] - self.ax.get_xlim()[0])/2 y = (self.ax.get_ylim()[1] - self.ax.get_ylim()[0])/2 self.ax.annotate(text, (x, y), zorder=1000000, xycoords="data", fontsize=18, ha='center', va='top', wrap=True) self.trigger() def _replace_figure_with_pyplot(self): """Deprecated!! workaround to fix bug of no dpi""" figure = plt.figure(figsize=(self.p_frame_width / self.dpi, self.p_frame_height / self.dpi), dpi=self.dpi) ax = plt.Axes(figure, [0., 0., 1., 1.]) figure.add_axes(ax) plt.close(figure) # close figure to prevent inline display ax.set_axis_off() self.figure = figure self.ax = ax self.frame.object = figure self.trigger() def start_server(self): """ Display the panel object in a new browser window Returns: """ # Check for instances and close them? self.panel.show(threaded=False) # , title="Sandbox frame!")#, port = 4242, use_reloader = False) # TODO: check how can check if the port exist/open and overwrite it logger.info('Projector initialized and server started.\n' 'Please position the browser window accordingly and enter fullscreen!') return True def clear_axes(self): """ Empty the axes of the current figure and trigger the update of the figure in the panel. Returns: """ self.ax.cla() self.trigger() return True def _clock(self): """ To to be sure that panel have enough time to display the figure he want. Solves issue #3 """ ctext = [isinstance(text, matplotlib.text.Text) for text in self.ax.texts] coll = [isinstance(coll, matplotlib.collections.PathCollection) for coll in self.ax.collections] if True in ctext or True in coll: sec = (len(coll)+len(ctext))*self._target_time # Give 0.005 ms to each Text from contours to be plotted self._paused_time = sec plt.pause(sec) else: self._paused_time = None def trigger(self): """ Update the panel figure if modified Returns: """ # self.figure.canvas.draw_idle() # TODO: do we need this or not? self.frame.param.trigger('object') self._clock() return True def save_json(self, file: str = 'projector_calibration.json'): """ Saves the current state of the projector in a .JSON calibration file Args: file: address to save the calibration Returns: """ with open(file, "w") as calibration_json: data = {'version': self.version, 'p_width': self.p_width, 'p_height': self.p_height, 'p_frame_top': self.p_frame_top, 'p_frame_left': self.p_frame_left, 'p_frame_width': self.p_frame_width, 'p_frame_height': self.p_frame_height, 'col_top': self.col_top, 'col_left': self.col_left, 'col_width': self.col_width, 'col_height': self.col_height, 'pos_colorbar': self.pos_colorbar, 'leg_top': self.leg_top, 'leg_left': self.leg_left, 'leg_width': self.leg_width, 'leg_height': self.leg_height, } json.dump(data, calibration_json) logger.info('JSON configuration file saved: %s' % str(file)) return True def load_json(self, file: str): """ Load a calibration file (.JSON format) and actualizes the panel parameters Args: file: address of the calibration to load Returns: """ def json_load(dict_data): if dict_data['version'] == self.version: self.p_width = dict_data.get('p_width') self.p_height = dict_data.get('p_height') self.p_frame_top = dict_data.get('p_frame_top') self.p_frame_left = dict_data.get('p_frame_left') self.p_frame_width = dict_data.get('p_frame_width') self.p_frame_height = dict_data.get('p_frame_height') self.col_top = dict_data.get('col_top') self.col_left = dict_data.get('col_left') self.col_width = dict_data.get('col_width') self.col_height = dict_data.get('col_height') self.pos_colorbar = dict_data.get('pos_colorbar') self.leg_top = dict_data.get('leg_top') self.leg_left = dict_data.get('leg_left') self.leg_width = dict_data.get('leg_width') self.leg_height =dict_data.get('leg_height') logger.info("JSON configuration loaded for projector") else: logger.warning("JSON configuration incompatible." + "\nPlease select a valid calibration file or start a new calibration!") if os.path.isfile(file): with open(file) as calibration_json: data = json.load(calibration_json) json_load(data) else: data = json.loads(file) json_load(data) return True def calibrate_projector(self): self._create_widgets() panel = pn.Column("### Projector dashboard arrangement", self._widget_p_frame_top, self._widget_p_frame_left, self._widget_p_frame_width, self._widget_p_frame_height, '<b>Save file<b>', self._widget_json_filename, self._widget_json_save ) return panel def show_widgets_sidepanels(self): tabs = pn.Tabs(("Colorbar", self.show_widget_colorbar()), ("Legend", self.show_widget_legend())) return tabs def show_widget_colorbar(self): self._create_widgets_colorbar() panel1 = pn.Column("### Colorbar", self._widgets_show_colorbar, self._widget_label, self._widget_refresh_col ) panel2 = pn.Column(self._widget_colorbar_ori, self._widget_top_colorbar, self._widget_left_colorbar, self._widget_width_colorbar, self._widget_height_colorbar, self._widget_col_background) return pn.Row(panel1, panel2) def show_widget_legend(self): self._create_widgets_legend() panel3 = pn.Column("### Legend", self._widgets_show_legend, self._widget_refresh_leg) panel4 = pn.Column(self._widget_top_legend, self._widget_left_legend, self._widget_width_legend, self._widget_height_legend, self._widget_leg_background) return pn.Row(panel3, panel4) def _create_widgets(self): # projector widgets and links self._widget_p_frame_top = pn.widgets.IntSlider(name='Main frame top margin', value=self.p_frame_top, start=0, end=self.p_height - 20) self._widget_p_frame_top.link(self.frame, callbacks={'value': self._callback_p_frame_top}) self._widget_p_frame_left = pn.widgets.IntSlider(name='Main frame left margin', value=self.p_frame_left, start=0, end=self.p_width - 20) self._widget_p_frame_left.link(self.frame, callbacks={'value': self._callback_p_frame_left}) self._widget_p_frame_width = pn.widgets.IntSlider(name='Main frame width', value=self.p_frame_width, start=10, end=self.p_width) self._widget_p_frame_width.link(self.frame, callbacks={'value': self._callback_p_frame_width}) self._widget_p_frame_height = pn.widgets.IntSlider(name='Main frame height', value=self.p_frame_height, start=10, end=self.p_height) self._widget_p_frame_height.link(self.frame, callbacks={'value': self._callback_p_frame_height}) self._widget_json_filename = pn.widgets.TextInput(name='Choose a calibration filename:') self._widget_json_filename.param.watch(self._callback_json_filename, 'value', onlychanged=False) self._widget_json_filename.value = _calibration_dir + 'my_projector_calibration.json' self._widget_json_save = pn.widgets.Button(name='Save calibration') self._widget_json_save.param.watch(self._callback_json_save, 'clicks', onlychanged=False) return True def _create_widgets_colorbar(self): self._widget_colorbar_ori = pn.widgets.Select(name='Orientation Colorbar', options=["vertical", "horizontal"], value=self.pos_colorbar) self._widget_colorbar_ori.param.watch(self._callback_colorbar_ori, 'value', onlychanged=False) self._widgets_show_colorbar = pn.widgets.Checkbox(name='Show colorbar', value=self.enable_colorbar) self._widgets_show_colorbar.param.watch(self._callback_enable_colorbar, 'value', onlychanged=False) self._widget_top_colorbar = pn.widgets.IntSlider(name='Top space', value=self.col_top, start=0, end=self.p_height - 20) self._widget_top_colorbar.param.watch(self._callback_top_colorbar, 'value', onlychanged=False) self._widget_left_colorbar = pn.widgets.IntSlider(name='Left space', value=self.col_left, start=0, end=self.p_width - 20) self._widget_left_colorbar.param.watch(self._callback_left_colorbar, 'value', onlychanged=False) self._widget_width_colorbar = pn.widgets.IntSlider(name='Width Colorbar', value=self.col_width, start=1, end=self.p_width) self._widget_width_colorbar.param.watch(self._callback_width_colorbar, 'value', onlychanged=False) self._widget_height_colorbar = pn.widgets.IntSlider(name='Height colorbar', value=self.col_height, start=1, end=self.p_height) self._widget_height_colorbar.param.watch(self._callback_height_colorbar, 'value', onlychanged=False) self._widget_label = pn.widgets.TextInput(name='Label of colorbar') self._widget_label.param.watch(self._callback_label, 'value', onlychanged=False) self._widget_refresh_col = pn.widgets.Button(name="Refresh label", button_type="success") self._widget_refresh_col.param.watch(self._callback_refresh, 'clicks', onlychanged=False) self._widget_col_background = pn.widgets.ColorPicker(name='Color background colorbar', value="#2896A5") self._widget_col_background.param.watch(self._callback_col_background, 'value', onlychanged=False) def _create_widgets_legend(self): self._widgets_show_legend = pn.widgets.Checkbox(name='Show legend', value=self.enable_legend) self._widgets_show_legend.param.watch(self._callback_enable_legend, 'value', onlychanged=False) self._widget_top_legend = pn.widgets.IntSlider(name='Top space', value=self.leg_top, start=0, end=self.p_height - 20) self._widget_top_legend.param.watch(self._callback_top_legend, 'value', onlychanged=False) self._widget_left_legend = pn.widgets.IntSlider(name='Left space', value=self.leg_left, start=0, end=self.p_width - 20) self._widget_left_legend.param.watch(self._callback_left_legend, 'value', onlychanged=False) self._widget_width_legend = pn.widgets.IntSlider(name='Width Legend', value=self.leg_width, start=1, end=self.p_width) self._widget_width_legend.param.watch(self._callback_width_legend, 'value', onlychanged=False) self._widget_height_legend = pn.widgets.IntSlider(name='Height Legend', value=self.leg_height, start=1, end=self.p_height) self._widget_height_legend.param.watch(self._callback_height_legend, 'value', onlychanged=False) self._widget_refresh_leg = pn.widgets.Button(name="Refresh legend", button_type="success") self._widget_refresh_leg.param.watch(self._callback_refresh_leg, 'clicks', onlychanged=False) self._widget_leg_background = pn.widgets.ColorPicker(name='Color background colorbar', value="#16425B") self._widget_leg_background.param.watch(self._callback_leg_background, 'value', onlychanged=False) def _callback_label(self, event): self._label = event.new if event.new != "" else None def _callback_refresh(self, event): self.set_colorbar(0, 1, label=self._label) def _callback_refresh_leg(self, event): self.set_legend() def _callback_enable_colorbar(self, event): self.enable_colorbar = event.new self.set_colorbar_widget() def _callback_enable_legend(self, event): self.enable_legend = event.new if self.enable_legend: self.create_legend() self.sidebar.insert(1, self.legend) else: if self.legend is not None: self.sidebar.remove(self.legend) if self.legend in self.sidebar else None def set_colorbar_widget(self): if self.colorbar is not None: for pa in self.panel: if self.colorbar in pa: pa.remove(self.colorbar) break if self.enable_colorbar: if self.pos_colorbar == "horizontal": self.create_colorbar() self.colorbar.margin = [0, 0, 0, self.p_frame_left] self.panel[0].insert(1, self.colorbar) elif self.pos_colorbar == "vertical": self.create_colorbar() self.sidebar.insert(0, self.colorbar) self._widget_height_colorbar.value = self.col_height = self.p_frame_height if self.pos_colorbar == "vertical" \ else round(self.p_frame_height / self._ratio) self._widget_width_colorbar.value = self.col_width = self.p_frame_width if self.pos_colorbar == "horizontal" \ else round(self.p_frame_width / self._ratio) self._widget_left_colorbar.value = self.col_left = 0 if self.pos_colorbar == "vertical" else self.p_frame_left self._widget_top_colorbar.value = self.col_top = 0 def _callback_colorbar_ori(self, event): self.pos_colorbar = event.new self.set_colorbar_widget() def _callback_top_colorbar(self, event): self.colorbar.margin[0] = event.new self.colorbar.param.trigger('object') def _callback_left_colorbar(self, event): self.colorbar.margin[-1] = event.new self.colorbar.param.trigger('object') def _callback_width_colorbar(self, event): self.colorbar.width = event.new self.colorbar.param.trigger('object') def _callback_height_colorbar(self, event): self.colorbar.height = event.new self.colorbar.param.trigger('object') def _callback_top_legend(self, event): self.leg_top = event.new self.legend.margin[0] = event.new self.legend.param.trigger('object') def _callback_left_legend(self, event): self.leg_left = event.new self.legend.margin[-1] = event.new self.legend.param.trigger('object') def _callback_width_legend(self, event): self.leg_width = event.new self.legend.width = event.new self.legend.param.trigger('object') def _callback_height_legend(self, event): self.leg_height = event.new self.legend.height = event.new self.legend.param.trigger('object') def _callback_p_frame_top(self, target, event): self.p_frame_top = event.new m = target.margin n = event.new # just changing single indices does not trigger updating of pane target.margin = [n, m[1], m[2], m[3]] def _callback_p_frame_left(self, target, event): self.p_frame_left = event.new m = target.margin n = event.new target.margin = [m[0], m[1], m[2], n] def _callback_p_frame_width(self, target, event): self.p_frame_width = event.new target.width = event.new target.param.trigger('object') def _callback_p_frame_height(self, target, event): self.p_frame_height = event.new target.height = event.new target.param.trigger('object') def _callback_json_filename(self, event): self.json_filename = event.new def _callback_json_save(self, event): if self.json_filename is not None: self.save_json(file=self.json_filename) def _callback_col_background(self, event): self.colorbar.background = event.new def _callback_leg_background(self, event): self.legend.background = event.new
class SeismicModule(ModuleTemplate): """ Follow the link to see the code that inspired the module https://nbviewer.jupyter.org/github/devitocodes/devito/blob/master/examples/seismic/tutorials/01_modelling.ipynb""" def __init__(self, extent: list = None, **kwargs): """Importing packages and setting correctly the path to the devito package, this beacuse we need the examples""" self.Load_Area = LoadSaveTopoModule(extent=extent, **kwargs) self.vp = None # Normalized or smoothed or None topography to be the velocity model self.model: Model = None # the model self.time_range = None # the time of the simulation self.src = None # the ricker source self.u = None # wavefield time function self.pde = None # PDE to solve. Wave equation with corresponding discretizations self.stencil = None # a time marching updating equation known as a stencil using customized SymPy functions self.src_coordinates = [] self.src_term = [] # all sources together self.rec = None self.rec_term = [] # all receivers # After constructing all the necessary expressions for updating the wavefield, # injecting the source term and interpolating onto the receiver points, we can now create the Devito operator self.op = None self.n_frames_speed = 10 self.frequency = 0.025 # Source peak frequency is 25Hz (0.025 kHz) # self.aruco_sources_coord = [] # For the cropping, because when normalizing the velocities dont work self.crop = True self.xy_aruco = [] # for the plotting self.timeslice = 0 self.threshold = 0.03 self.field = None self.p_velocity = True self.ready_velocity = False self.p_wave = True self.ready_wave = False self.framerate = 10 self._vp = None self._w = None self.real_time = False self.model_extent = None self.frame = None self.extent = None self.max_wave_frame = 1 # Widgets self.lock = None self.figure = Figure() self.axes = Axes(self.figure, [0., 0., 1., 1.]) self.figure.add_axes(self.axes) self.panel_figure = pn.pane.Matplotlib(self.figure, tight=True) plt.close(self.figure) # close figure to prevent inline display logger.info("SeismicModule loaded successfully") def update(self, sb_params: dict): frame = sb_params.get('frame') ax = sb_params.get('ax') marker = sb_params.get('marker') self.extent = sb_params.get('extent')[:4] self.lock = sb_params.get("lock_thread") sb_params = self.Load_Area.update(sb_params) if self.crop: self.frame = np.transpose(self.crop_frame(frame)) else: self.frame = np.transpose(frame) if len(marker) > 0: self.xy_aruco = marker.loc[marker.is_inside_box, ('box_x', 'box_y')].values else: self.xy_aruco = [] self.plot(ax) return sb_params def plot(self, ax): if self.p_velocity and self.ready_velocity: self.plot_seismic_velocity(ax) else: self.delete_seismic_velocity() if self.p_wave and self.ready_wave: self.plot_wavefield(ax) else: self.delete_wavefield() ax.set_axis_off() ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) def plot_seismic_velocity(self, ax): if self.field is not None: if self._vp is None: self._vp = ax.imshow(self.field, cmap=plt.get_cmap("jet"), vmin=np.min(self.field), vmax=np.max(self.field), extent=self.Load_Area.to_box_extent if self.crop else self.extent, origin="lower", zorder=2) else: self._vp.set_data(self.field) def delete_seismic_velocity(self): if self._vp is not None: self._vp.remove() self._vp = None def plot_wavefield(self, ax): if self.u is not None and self.model is not None: if self._w is None: self._w = ax.imshow(self.wavefield(self.timeslice), vmin=-1e0, vmax=1e0, cmap=plt.get_cmap('seismic'), aspect=1, extent=self.Load_Area.to_box_extent if self.crop else self.extent, interpolation='none', origin="lower", zorder=3) else: self._w.set_data(self.wavefield(self.timeslice)) if self.real_time: self.timeslice += self.framerate if self.timeslice >= self.time_range.num: self.timeslice = 0 def delete_wavefield(self): if self._w is not None: self._w.remove() self._w = None def run_simulation(self, vmin=2, vmax=4, nbl=40, **kwargs): if self.model is None: self.init_model(vmin=vmin, vmax=vmax, frame=self.frame, nbl=nbl, **kwargs) if len(self.src_coordinates) == 0: logger.warning("Put an aruco marker as a source or manually specify a source term") return self.insert_aruco_source() self.operator_and_solve() logger.info("Simulation succesfull") def init_model(self, vmin, vmax, frame=None, **kwargs): if frame is None: frame = self.frame self.create_velocity_model(frame, vmax=vmax, vmin=vmin, **kwargs) self.create_time_axis(**kwargs) self.create_time_function() self.solve_PDE() def insert_aruco_source(self): if self.model is None: logger.warning("Create the velocity model first") return if len(self.xy_aruco) > 0: self.src_term = [] for counter, aru in enumerate(self.xy_aruco): # Modify to the simulation area aru_mod = (aru[0] - self.Load_Area.box_origin[0], aru[1] - self.Load_Area.box_origin[1]) src = self.create_source(name="src%i" % counter, f0=self.frequency, source_coordinates=(aru_mod[0]*self.model.spacing[0], aru_mod[1]*self.model.spacing[1]), show_wavelet=False, show_model=False) self.inject_source(src) else: logger.warning("No arucos founded") return def crop_frame(self, frame): return frame[self.Load_Area.box_origin[1]:self.Load_Area.box_origin[1] + self.Load_Area.box_height, self.Load_Area.box_origin[0]:self.Load_Area.box_origin[0] + self.Load_Area.box_width] def scale_linear(self, topo: np.ndarray, high: float, low: float): """ scale the frame data according to the highest and lowest value desired Args: topo: topo frame high: max value low: min value Returns: Normalized frame """ mins = np.amin(topo) maxs = np.amax(topo) rng = maxs - mins return high - (((high - low) * (maxs - topo)) / rng) def smooth_topo(self, topo: np.ndarray, sigma_x: int, sigma_y: int): """ Smoothing the topography... Args: topo: topo frame sigma_x: smooth in x direction sigma_y: smooth in y direction Returns: Smothed array """ return ndimage.filters.gaussian_filter(topo, [sigma_y, sigma_x], mode='nearest') def create_velocity_model(self, topo: np.ndarray, norm: bool=True, vmax: float = 5.0, vmin: float = 2.0, smooth: bool = False, sigma_x: int = 2, sigma_y: int = 2, spacing: tuple = (10, 10), origin=(0, 0), nbl: int = 40, show_velocity: bool = False, **kwargs): """ takes the topography and creates a velocity model from the topography Args: topo: topo array norm: to normalize the topo according to vmax and vmin vmax: maximum velocity for normalization vmin: minimum velocity for normalization smooth: to apply a gaussian filter to the topo sigma_x: smooth in x direction sigma_y: smooth in y_direction spacing: Grid spacing in m origin: What is the location of the top left corner. This is necessary to define the absolute location of the source and receivers nbl: size of the absorbing layer show_velocity: plot of the velocity model Returns: model """ if topo is None: # Make a simple 2 layered velocity model vp = np.empty((101, 101), dtype=np.float32) vp[:, :51] = 1.5 vp[:, 51:] = 2.5 topo = vp topo = topo.astype(np.float32) if norm: topo = self.scale_linear(topo, vmax, vmin) if smooth: topo = self.smooth_topo(topo, sigma_x, sigma_y) self.vp = np.transpose(topo) self.model = Model(vp=topo, origin=origin, shape=topo.shape, spacing=spacing, space_order=2, nbl=nbl, bcs="damp") slices = tuple(slice(self.model.nbl, -self.model.nbl) for _ in range(2)) if getattr(self.model, 'vp', None) is not None: self.field = self.model.vp.data[slices] else: self.field = self.model.lam.data[slices] self.field = np.transpose(self.field) self.ready_velocity = True domain_size = 1.e-3 * np.array(self.model.domain_size) # To express in kilometers self.model_extent = [self.model.origin[0], self.model.origin[0] + domain_size[0], self.model.origin[1], self.model.origin[1] + domain_size[1]] if show_velocity: self.show_velocity(self.model) return self.model def create_time_axis(self, t0: int = 0, tn: int = 1000): """ Time duration of our model. This takes the start, and end with the time-step-size provided by the model Args: t0: Simulation starts a t=0 tn: Simulation last 1 second (1000 ms) Returns: Time_range """ dt = self.model.critical_dt self.time_range = TimeAxis(start=t0, stop=tn, step=dt) self.max_wave_frame = self.time_range.num - 1 return self.time_range @property def _src_coords(self): """gives the source coordinates of the richter waveletet in the middle of the model""" return np.multiply([int(self.model.domain_size[0]/2), int(self.model.domain_size[1]/2/2)], [10, 10]) def create_source(self, name: str = 'src', f0: float = 0.025, source_coordinates: tuple = None, show_wavelet: bool = False, show_model: bool = False): """ RickerSource positioned at a depth of "depth_source" Args: name: assign a name to the source, so we can distinguish if more sources f0: # Source peak frequency is 25Hz (0.025 kHz) source_coordinates: position (x, y) for the source. Scale is in meters show_wavelet: Plot the time signature to see the wavelet show_model: plot the velocity model and the location of the source Returns: """ if source_coordinates is None: source_coordinates = self._src_coords src = RickerSource(name=name, grid=self.model.grid, f0=f0, npoint=1, time_range=self.time_range, coordinates=source_coordinates) # First, position source centrally in all dimensions, then set depth # src.coordinates.data[0, :] = np.array(model.domain_size) * .5 # src.coordinates.data[0, -1] = 20. # Depth is 20m if show_wavelet: # We can plot the time signature to see the wavelet src.show() if show_model: self.show_velocity(self.model, source=src.coordinates.data) return src def create_time_function(self): """ second order time discretization: This derivative is represented in Devito by u.dt2 where u is a TimeFunction object. Spatial discretization: This derivative is represented in Devito by u.laplace where u is a TimeFunction object. With space and time discretization defined, we can fully discretize the wave-equation with the combination of time and space discretizations Returns: """ # Define the wavefield with the size of the model and the time dimension self.u = TimeFunction(name="u", grid=self.model.grid, time_order=2, space_order=2, save=self.time_range.num) # We can now write the PDE self.pde = self.model.m * self.u.dt2 - self.u.laplace + self.model.damp * self.u.dt return self.pde def solve_PDE(self): """This discrete PDE can be solved in a time-marching way updating u(t+dt) from the previous time step""" self.stencil = Eq(self.u.forward, solve(self.pde, self.u.forward)) return self.stencil def inject_source(self, source): """ For every RickerSource we need to add it to the numerical scheme in order to solve the homogenous wave equation, in order to implement the measurement operator and interpolator operator. Args: source: from the self.create_source() Returns: """ src_term = source.inject(field=self.u.forward, expr=source * self.model.critical_dt ** 2 / self.model.m) # TODO: offset=model.nbl)) if self.src_term == []: self.src_term = src_term else: self.src_term += src_term self.src_coordinates.append(source.coordinates.data) logger.info("Source registered") return self.src_term def create_receivers(self, name: str = 'rec', n_receivers: int = 50, depth_receivers: int = 20, show_receivers: bool = False): """ Interpolate the values of the receivers horizontaly at a depth Args: name: name to the receivers n_receivers: amount of points/receivers depth_receivers: to plot the receivers along the x axis of the coordinate show_receivers: show a plot with receiver data Returns: """ x_locs = np.linspace(0, self.model.shape[0]*self.model.spacing[0], n_receivers) rec_coords = [(x, depth_receivers) for x in x_locs] rec = Receiver(name=name, npoint=n_receivers, time_range=self.time_range, grid=self.model.grid, coordinates=rec_coords) if show_receivers: self.show_velocity(self.model, receiver=rec.coordinates.data[::4, :]) return rec def interpolate_receiver(self, rec): """obtain the receivers information""" self.rec_term = rec.interpolate(expr=self.u.forward) return self.rec_term def operator_and_solve(self): """ After constructing all the necessary expressions for updating the wavefield, injecting the source term and interpolating onto the receiver points, we can now create the Devito operator that will generate the C code at runtime. Returns: """ self.op = Operator([self.stencil] + self.src_term + self.rec_term) # , subs=self.model.spacing_map) self.op(dt=self.model.critical_dt) self.ready_wave = True def wavefield(self, timeslice): """get rid of the sponge that attenuates the waves""" if timeslice >= self.time_range.num: logger.info('timeslice not valid for value %i, setting values of %i' % (timeslice, self.time_range.num-1)) timeslice = self.time_range.num-1 wf_data = self.u.data[timeslice, self.model.nbl:-self.model.nbl, self.model.nbl:-self.model.nbl] wf_data_normalize = wf_data / np.amax(wf_data) waves = np.ma.masked_where(np.abs(wf_data_normalize) <= self.threshold, wf_data_normalize) return np.transpose(waves) def show_wavefield(self, timeslice: int): """ Gives a plot of the wavefield in time (ms) Args: timeslice: value in ms Returns: """ fig, ax = plt.subplots() model_param = dict(vmin=self.vp.max(), vmax=self.vp.min(), cmap=plt.get_cmap('jet'), aspect=1, extent=self.model_extent, origin="lower") data_param = dict(vmin=-1e0, vmax=1e0, cmap=plt.get_cmap('seismic'), aspect=1, extent=self.model_extent, interpolation='none', origin="lower") _vp = plt.imshow(self.vp, **model_param) _wave = plt.imshow(self.wavefield(timeslice), **data_param) ax.set_ylabel('Depth (km)', fontsize=20) ax.set_xlabel('x position (km)', fontsize=20) ax.set_title("t = {:.0f} ms".format(timeslice*self.time_range.step)) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) fig.colorbar(_vp, cax=cax, ax=ax, label="Velocity (km/s)") fig.show() def show_velocity(self, model, source=None, receiver=None, cmap="jet"): """ Function modified from DEVITO example codes Plot a two-dimensional velocity field from a seismic `Model` object. Optionally also includes point markers for sources and receivers. Parameters ---------- model : Model Object that holds the velocity model. source : array_like or float Coordinates of the source point. receiver : array_like or float Coordinates of the receiver points. cmap : "jet" """ slices = tuple(slice(model.nbl, -model.nbl) for _ in range(2)) if getattr(model, 'vp', None) is not None: field = model.vp.data[slices] else: field = model.lam.data[slices] field = np.transpose(field) fig, ax = plt.subplots() plot = ax.imshow(field, animated=True, cmap=cmap, vmin=np.min(field), vmax=np.max(field), extent=self.model_extent, origin="lower") ax.set_xlabel('X position (km)') ax.set_ylabel('Depth (km)') # Plot receiver points, if provided if receiver is not None: ax.scatter(1e-3 * receiver[:, 0], 1e-3 * receiver[:, 1], s=25, c='green', marker='D') # Plot source points, if provided if source is not None: if not isinstance(source, list): source = [source] for sou in source: ax.scatter(1e-3 * sou[:, 0], 1e-3 * sou[:, 1], s=25, c='red', marker='o') # Ensure axis limits ax.set_xlim(self.model_extent[0], self.model_extent[1]) ax.set_ylim(self.model_extent[2], self.model_extent[3]) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) fig.colorbar(plot, cax=cax, ax=ax, label="Velocity (km/s)") fig.show() def update_panel_plot(self): self.figure.clf() self.axes.cla() self.figure.add_axes(self.axes) model_param = dict(vmin=self.vp.max(), vmax=self.vp.min(), cmap=plt.get_cmap('jet'), aspect=1, extent=self.model_extent, origin="lower") _vp = self.axes.imshow(self.vp, **model_param) self.axes.set_ylabel('Depth (km)') self.axes.set_xlabel('x position (km)') if self.p_wave and self.ready_wave: data_param = dict(vmin=-1e0, vmax=1e0, cmap=plt.get_cmap('seismic'), aspect=1, extent=self.model_extent, interpolation='none', origin="lower") _wave = self.axes.imshow(self.wavefield(self.timeslice), **data_param) self.axes.set_title("t = {:.0f} ms".format(self.timeslice*self.time_range.step)) # Plot source points, if provided if self.src_coordinates is not None and len(self.src_coordinates) > 0: for sou in self.src_coordinates: self.axes.scatter(1e-3 * sou[:, 0], 1e-3 * sou[:, 1], s=25, c='red', marker='o') # Ensure axis limits self.axes.set_xlim(self.model_extent[0], self.model_extent[1]) self.axes.set_ylim(self.model_extent[2], self.model_extent[3]) divider = make_axes_locatable(self.axes) cax = divider.append_axes("right", size="5%", pad=0.05) self.figure.colorbar(_vp, cax=cax, ax=self.axes, label="Velocity (km/s)") self.panel_figure.param.trigger("object") def show_shotrecord(self, rec, model, t0, tn): """ function modified from DEVITO example codes Plot a shot record (receiver values over time). Parameters ---------- rec : Receiver data with shape (time, points). model : Model object that holds the velocity model. t0 : int Start of time dimension to plot. tn : int End of time dimension to plot. """ scale = np.max(rec) / 10. extent = [model.origin[0], model.origin[0] + 1e-3 * model.domain_size[1], 1e-3 * tn, t0] fig, ax = plt.subplots() plot = ax.imshow(rec, vmin=-scale, vmax=scale, cmap=cm.gray, extent=extent) ax.set_xlabel('X position (km)') ax.set_ylabel('Time (s)') divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) fig.colorbar(plot, cax=cax, ax=ax) fig.show() def show_widgets(self): panel = pn.Row(self.show_simulation_widgets(), self.show_plotting_widgets()) tabs = pn.Tabs(("Seismic", panel), ("LoadSaveModule", self.Load_Area.show_widgets())) return tabs def show_plotting_widgets(self): self._widget_real_time = pn.widgets.Checkbox(name='Real time', value=self.real_time) self._widget_real_time.param.watch(self._callback_real_time, 'value', onlychanged=False) self._widget_framerate = pn.widgets.Spinner(name='Framerate', value=self.framerate, step=1) self._widget_framerate.param.watch(self._callback_framerate, 'value', onlychanged=False) self._widget_wave_selector = pn.widgets.IntSlider(name='Wavefield in frame', value=self.timeslice, start=0, end=self.max_wave_frame) self._widget_wave_selector.param.watch(self._callback_select_wave, 'value', onlychanged=False) self._widget_p_velocity = pn.widgets.Checkbox(name='Velocity Model', value=self.p_velocity) self._widget_p_velocity.param.watch(self._callback_p_velocity, 'value', onlychanged=False) self._widget_p_wavefield = pn.widgets.Checkbox(name='Wavefield', value=self.p_wave) self._widget_p_wavefield.param.watch(self._callback_p_wavefield, 'value', onlychanged=False) self._widget_threshold = pn.widgets.Spinner(name='Wavefield threshold', value=self.threshold, step=0.01) self._widget_threshold.param.watch(self._callback_threshold, 'value', onlychanged=False) panel = pn.Column("### <b>Controllers</b>", self.panel_figure, "<b>Show Seismic wave in real time</b>", self._widget_real_time, self._widget_framerate, self._widget_threshold, "<b>Visualize single seismic wave</b> (First deactivate real time)", self._widget_wave_selector, "<b>Hide or show velocity model and wavefield</b>", self._widget_p_velocity, self._widget_p_wavefield ) return panel def show_simulation_widgets(self): self._widget_vmin = pn.widgets.Spinner(name="vmin", value=2.0, step=0.1) self._widget_vmax = pn.widgets.Spinner(name="vmax", value=5.0, step=0.1) self._widget_nbl = pn.widgets.Spinner(name="Damping thickness", value=40, step=1) self._widget_create_model = pn.widgets.Button(name="Create velocity model", button_type="success") self._widget_create_model.param.watch(self._callback_velocity_model, 'clicks', onlychanged=False) self._widget_t0 = pn.widgets.Spinner(name="t0", value=0, step=1) self._widget_tn = pn.widgets.Spinner(name="tn", value=800, step=1) self._widget_create_time = pn.widgets.Button(name="Create time axis", button_type="success") self._widget_create_time.param.watch(self._callback_create_time, 'clicks', onlychanged=False) self._widget_frequency = pn.widgets.Spinner(name="Frequency (Hz)", value=self.frequency*1000, step=1) self._widget_insert_aruco = pn.widgets.Button(name="Insert sources", button_type="warning") self._widget_insert_aruco.param.watch(self._callback_insert_aruco, 'clicks', onlychanged=False) self._widget_solve = pn.widgets.Button(name="Solve PDE", button_type="success") self._widget_solve.param.watch(self._callback_solve, 'clicks', onlychanged=False) column = pn.Column("### <b>Simulation</b>", "<b>1) Costruct velocity model</b>", self._widget_vmax, self._widget_vmin, self._widget_nbl, self._widget_create_model, "<b>2) Create time axis and functions</b>", self._widget_t0, self._widget_tn, self._widget_create_time, "<b>3) Insert source terms</b>", "Place aruco markers in position and click the button", self._widget_frequency, self._widget_insert_aruco, "<b>4) Solve", self._widget_solve) return column def _callback_threshold(self, event): self.threshold = event.new def _callback_velocity_model(self, event): self.lock.acquire() vmin = self._widget_vmin.value vmax = self._widget_vmax.value nbl = self._widget_nbl.value _ = self.create_velocity_model(topo=self.frame, vmax=vmax, vmin=vmin, nbl=nbl) self.update_panel_plot() self.lock.release() def _callback_create_time(self, event): self.lock.acquire() t0 = self._widget_t0.value tn = self._widget_tn.value _ = self.create_time_axis(t0, tn) self._widget_wave_selector.end = self.max_wave_frame _ = self.create_time_function() _ = self.solve_PDE() self.lock.release() def _callback_insert_aruco(self, event): self.lock.acquire() self.frequency = self._widget_frequency.value/1000 # (to put in kHz) self.insert_aruco_source() self.update_panel_plot() self.lock.release() def _callback_solve(self, event): self.lock.acquire() self.operator_and_solve() self.update_panel_plot() self.lock.release() def _callback_real_time(self, event): self.real_time = event.new def _callback_framerate(self, event): self.framerate = event.new def _callback_select_wave(self, event): self.lock.acquire() self.timeslice = event.new self.update_panel_plot() self.lock.release() def _callback_p_velocity(self, event): self.p_velocity = event.new def _callback_p_wavefield(self, event): self.p_wave = event.new
def cla(self): """Clear axes and disable mouse button callbacks. """ self.disable_mouse_rotation() Axes.cla(self) self.grid(rcParams['axes3d.grid'])