import logging import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk class BedMap(Gtk.DrawingArea): def __init__(self, font_size, bm): super().__init__() self.set_hexpand(True) self.set_vexpand(True) self.connect('draw', self.draw_graph) self.font_size = font_size self.font_spacing = round(self.font_size * 1.5) self.bm = list(reversed(bm)) if bm is not None else None self.invert_x = False self.invert_y = False self.rotation = 0 self.mesh_min = [0, 0] self.mesh_max = [0, 0] self.mesh_radius = 0 def update_bm(self, bm): if not bm: self.bm = None return for key, value in bm.items(): if key == 'profiles': continue logging.info(f"{key}: {value}") if 'mesh_min' in bm: self.mesh_min = bm['mesh_min'] self.mesh_max = bm['mesh_max'] if 'mesh_radius' in bm: self.mesh_radius = bm['mesh_radius'] if 'probed_matrix' in bm: bm = bm['probed_matrix'] elif 'points' in bm: bm = bm['points'] else: self.bm = None return if self.invert_x and self.invert_y: self.rotation = (self.rotation + 180) % 360 self.invert_x = self.invert_y = False if self.invert_x: new_max = [self.mesh_min[0], self.mesh_max[1]] new_min = [self.mesh_max[0], self.mesh_min[1]] self.mesh_max = new_max self.mesh_min = new_min self.bm = [list(reversed(b)) for b in list(reversed(bm))] if self.invert_y: new_max = [self.mesh_max[0], self.mesh_min[1]] new_min = [self.mesh_min[0], self.mesh_max[1]] self.mesh_max = new_max self.mesh_min = new_min self.bm = list(bm) else: self.bm = list(reversed(bm)) if self.rotation in (90, 180, 270): self.bm = self.rotate_matrix(self.bm) def rotate_matrix(self, matrix): if self.rotation == 90: new_max = [self.mesh_max[1], self.mesh_min[0]] new_min = [self.mesh_min[1], self.mesh_max[0]] self.mesh_max = new_max self.mesh_min = new_min return [list(row) for row in zip(*matrix[::-1])] elif self.rotation == 180: new_max = [self.mesh_min[0], self.mesh_min[1]] new_min = [self.mesh_max[0], self.mesh_max[1]] self.mesh_max = new_max self.mesh_min = new_min return [list(row)[::-1] for row in matrix[::-1]] elif self.rotation == 270: new_max = [self.mesh_min[1], self.mesh_max[0]] new_min = [self.mesh_max[1], self.mesh_min[0]] self.mesh_max = new_max self.mesh_min = new_min return [list(row) for row in zip(*matrix)][::-1] def draw_graph(self, da, ctx): width = da.get_allocated_width() height = da.get_allocated_height() gwidth = int(width - self.font_size * 2.2) gheight = int(height - self.font_size * 1.8) # Styling ctx.set_line_width(1) ctx.set_font_size(self.font_size) if self.bm is None: ctx.move_to(self.font_spacing, height / 2) ctx.set_source_rgb(0.5, 0.5, 0.5) ctx.show_text(_("No mesh has been loaded")) ctx.stroke() return if not self.mesh_radius: text_side_top = [0, self.font_size] text_side_bottom = [0, height - int(self.font_size * 2)] text_side_middle = [self.font_size, (text_side_top[1] + text_side_bottom[1]) / 2] text_bottom_left = [self.font_size * 1.8, height - int(self.font_size / 2)] text_bottom_right = [width - int(self.font_size * 2.2), height - int(self.font_size / 2)] text_bottom_middle = [int(self.font_size * 2 + gwidth / 2), height - int(self.font_size / 2)] # dibujar ejes ctx.set_source_rgb(0.5, 0.5, 0.5) ctx.move_to(*text_side_top) ctx.show_text(f"{self.mesh_max[1]:.0f}".rjust(4, " ")) ctx.move_to(*text_side_bottom) ctx.show_text(f"{self.mesh_min[1]:.0f}".rjust(4, " ")) ctx.move_to(*text_bottom_left) ctx.show_text(f"{self.mesh_min[0]:.0f}".rjust(4, " ")) ctx.move_to(*text_bottom_right) ctx.show_text(f"{self.mesh_max[0]:.0f}".rjust(4, " ")) ctx.move_to(*text_side_middle) ctx.show_text(f"{'Y' if self.rotation == 0 or self.rotation == 180 else 'X'}") ctx.move_to(*text_bottom_middle) ctx.show_text(f"{'X' if self.rotation == 0 or self.rotation == 180 else 'Y'}") ctx.stroke() rows = len(self.bm) columns = len(self.bm[0]) for i, row in enumerate(self.bm): ty = (gheight / rows * i) by = ty + gheight / rows for j, column in enumerate(row): lx = (gwidth / columns * j) + self.font_size * 2.2 rx = lx + gwidth / columns # Colors ctx.set_source_rgb(*self.colorbar(column)) ctx.move_to(lx, ty) ctx.line_to(lx, by) ctx.line_to(rx, by) ctx.line_to(rx, ty) ctx.close_path() ctx.fill() ctx.stroke() if rows > 16 or columns > 8: continue # Numbers ctx.set_source_rgb(0, 0, 0) if column > 0: ctx.move_to((lx + rx) / 2 - self.font_size, (ty + by + self.font_size) / 2) else: ctx.move_to((lx + rx) / 2 - self.font_size * 1.2, (ty + by + self.font_size) / 2) ctx.show_text(f"{column:.2f}") ctx.stroke() @staticmethod def colorbar(value): rmax = 0.25 color = min(1, max(0, 1 - 1 / rmax * abs(value))) if value > 0: return [1, color, color] if value < 0: return [color, color, 1] return [1, 1, 1] def set_inversion(self, x=False, y=False): self.invert_x = x self.invert_y = y def set_rotation(self, rotation=0): self.rotation = rotation