class Ball2: """Class containg a n number of balls. It uses vispy to visualization.""" def __init__(self, position, velocity, boundaries = None, color = (1.0, 1.0, 1.0, 1.0)): self.n = position.shape[0] self.pos = position self.vel = velocity self.color = color self.rad = 0.1 self.bound = None self.sizexyz = [None] * 3 if boundaries is not None: self.set_bound(boundaries) self.visual = None def set_bound(self, boundaries): """Updates the boundaries.""" self.bound = boundaries self.sizexyz = np.abs(boundaries[:,1] - boundaries[:,0]) def step(self, time_step): """Calculate the new positions and speeds for all balls.""" despl = self.vel * time_step self.pos = self.pos + despl for i in range(3): if self.sizexyz[i] is not None: #-INF offbound = np.where(self.pos[:,i] < self.bound[i,0]) #-INF self.pos[offbound,i] = self.pos[offbound,i] + self.sizexyz[i] #-INF offbound = np.where(self.pos[:,i] > self.bound[i,1]) #-INF self.pos[offbound,i] = self.pos[offbound,i] - self.sizexyz[i] offbound = np.where(self.pos[:,i] < self.bound[i,0]) self.pos[offbound,i] = self.pos[offbound,i] - despl[offbound,i] self.vel[offbound,i] = - self.vel[offbound,i] * 0.8 offbound = np.where(self.pos[:,i] > self.bound[i,1]) self.pos[offbound,i] = self.pos[offbound,i] - despl[offbound,i] self.vel[offbound,i] = - self.vel[offbound,i] * 0.95 self.vel[:,2] = self.vel[:,2] - 0.1 self.update_visual() def init_visual(self, view): """Initialize the object visual.""" num_seg = sphere_pt.shape[0] all_seg = np.zeros((num_seg * self.n, 3)) for i in range(self.n): all_seg[i * num_seg: (i + 1) * num_seg] = sphere_pt * self.rad + self.pos[i,:] self.visual = Line(pos = all_seg, color=self.color, connect='segments') view.add(self.visual) def update_visual(self): """Updates the object visual.""" num_seg = sphere_pt.shape[0] all_seg = np.zeros((num_seg * self.n, 3)) for i in range(self.n): all_seg[i * num_seg: (i + 1) * num_seg] = sphere_pt * self.rad + self.pos[i,:] self.visual.set_data(pos = all_seg) def shake(self): """Inverts the z position and gives all the balls random velocity.""" if self.sizexyz[2] is not None: self.pos[:,2] = self.bound[2, 1] - (self.pos[:,2] - self.bound[2, 0]) self.vel = (np.random.rand(self.n, 3) - 0.5) * 10
class Balloon: """Balloon Class. It uses vispy to visualization.""" def __init__(self, position, velocity, boundaries = None, color = (1.0, 1.0, 1.0, 1.0)): self.pos = position self.vel = velocity self.color = color self.rad = 0.5 self.bound = None self.sizexyz = [None] * 3 if boundaries is not None: self.set_bound(boundaries) self.visual = None def set_bound(self, boundaries): """Updates the boundaries.""" self.bound = boundaries self.sizexyz = np.abs(boundaries[:,1] - boundaries[:,0]) def step(self, time_step): """Does nothing.""" pass def init_visual(self, view): """Initialize the object visual.""" self.visual = Line(pos = sphere_pt * self.rad + self.pos, color=self.color) view.add(self.visual) def update_visual(self): """Updates the object visual.""" self.visual.set_data(pos = sphere_pt * self.rad + self.pos) def shake(self): """Changes to a random color.""" self.color = np.random.rand(4) / 2 + 0.5 self.visual.set_data(color=self.color)
class Ball_trace: """Ball Class. It uses vispy to visualization.""" def __init__(self, position, velocity, boundaries = None, color = (1.0, 1.0, 1.0, 1.0)): self.pos = position self.vel = velocity self.color = color self.rad = 0.1 self.bound = None self.sizexyz = [None] * 3 self.tail_steps = 20 if boundaries is not None: self.set_bound(boundaries) self.visual = [None] def set_bound(self, boundaries): """Updates the boundaries.""" self.bound = boundaries self.sizexyz = np.abs(boundaries[:,1] - boundaries[:,0]) def step(self, time_step): """Calculate the new position and speed.""" despl = self.vel * time_step self.pos = self.pos + despl for i in range(3): #-INF if self.sizexyz[i] is not None and self.pos[i] < self.bound[i,0]: #-INF self.pos[i] = self.pos[i] + self.sizexyz[i] #-INF elif self.sizexyz[i] is not None and self.pos[i] > self.bound[i,1]: #-INF self.pos[i] = self.pos[i] - self.sizexyz[i] if self.sizexyz[i] is not None: if self.pos[i] < self.bound[i,0] or self.pos[i] > self.bound[i,1]: self.pos[i] = self.pos[i] - despl[i] self.vel[i] = - self.vel[i] * 0.95 self.vel[2] = self.vel[2] - 0.1 self.update_visual() def init_visual(self, view): """Initialize the object visual.""" self.trace = np.repeat(self.pos, self.tail_steps).reshape((3,self.tail_steps)).T pos = np.concatenate([sphere_pt * self.rad + self.pos, self.trace]) self.visual = Line(pos = pos, color=self.color) view.add(self.visual) def update_visual(self): """Updates the object visual.""" self.trace[1:] = self.trace[0:-1] self.trace[0] = self.pos pos = np.concatenate([sphere_pt * self.rad + self.pos, self.trace]) self.visual.set_data(pos = pos) def shake(self): """Inverts the z position and gives the ball a random velocity.""" if self.sizexyz[2] is not None: self.pos[2] = self.bound[2, 1] - (self.pos[2] - self.bound[2, 0]) self.vel = (np.random.rand(3) - 0.5) * 10 self.trace = np.repeat(self.pos, self.tail_steps).reshape((3,self.tail_steps)).T
def __init__(self, **kwds): verts = np.array([[0, 0, 0], [1, 0, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 0, 1]]) color = np.array([[1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1]]) Line.__init__(self, pos=verts, color=color, connect='segments', mode='gl', **kwds)
def init_visual(self, view): """Initialize the object visual.""" self.trace = np.repeat(self.pos, self.tail_steps).reshape((3,self.tail_steps)).T self.trace[:,0] = range(self.tail_steps,0,-1) self.trace = self.trace / 100 self.visual = Line(pos = self.trace, color=self.color) view.add(self.visual)
def init_visual(self, view): """Initialize the object visual.""" num_seg = sphere_pt.shape[0] all_seg = np.zeros((num_seg * self.n, 3)) for i in range(self.n): all_seg[i * num_seg: (i + 1) * num_seg] = sphere_pt * self.rad + self.pos[i,:] self.visual = Line(pos = all_seg, color=self.color, connect='segments') view.add(self.visual)
class Mouse_trace: """Mouse tracing Class. It uses vispy to visualization.""" def __init__(self, color = (1.0, 1.0, 1.0, 1.0)): self.mouse = PyMouse() self.pos = np.asarray([0, 0, 0]) self.color = color self.rad = 20.0 size = self.mouse.screen_size() boundaries = np.asarray([[0, size[0]], [0, size[1]], [0, 1]]) print(boundaries) self.sizexyz = [None] * 3 self.tail_steps = 200 self.set_bound(boundaries) self.visual = [None] def set_bound(self, boundaries): """Updates the boundaries.""" self.bound = boundaries self.sizexyz = np.abs(boundaries[:,1] - boundaries[:,0]) def step(self, time_step): """Calculate the new position and speed.""" mpos = self.mouse.position() self.pos = np.asarray([mpos[0], self.bound[1,1] - mpos[1], 0]) self.update_visual() def init_visual(self, view): """Initialize the object visual.""" self.trace = np.repeat(self.pos, self.tail_steps).reshape((3,self.tail_steps)).T pos = np.concatenate([sphere_pt * self.rad + self.pos, self.trace]) self.visual = Line(pos = pos, color=self.color) view.add(self.visual) def update_visual(self): """Updates the object visual.""" self.trace[1:] = self.trace[0:-1] self.trace[0] = self.pos pos = np.concatenate([sphere_pt * self.rad + self.pos, self.trace]) self.visual.set_data(pos = pos) def shake(self): """Inverts the z position and gives the ball a random velocity.""" pass
class Cpu_trace: """Mouse tracing Class. It uses vispy to visualization.""" def __init__(self, color = (1.0, 1.0, 1.0, 1.0)): self.pos = np.asarray([0, 0, 0], dtype = np.float32) self.color = color self.sizexyz = [None] * 3 self.tail_steps = 100 self.bound = None self.visual = [None] def set_bound(self, boundaries): """Updates the boundaries.""" self.bound = boundaries self.sizexyz = np.abs(boundaries[:,1] - boundaries[:,0]) def step(self, time_step): """Calculate the new position and speed.""" cpu = np.float(cpuutilization.get_utilization()) self.pos = np.asarray([100, cpu, 0]) self.update_visual() def init_visual(self, view): """Initialize the object visual.""" self.trace = np.repeat(self.pos, self.tail_steps).reshape((3,self.tail_steps)).T self.trace[:,0] = range(self.tail_steps,0,-1) self.trace = self.trace / 100 self.visual = Line(pos = self.trace, color=self.color) view.add(self.visual) def update_visual(self): """Updates the object visual.""" self.trace[1:,1] = self.trace[0:-1,1] self.trace[0] = self.pos / 100 self.visual.set_data(pos = self.trace) def shake(self): """Inverts the z position and gives the ball a random velocity.""" pass
def __init__(self, layer): # Create a compound visual with the following four subvisuals: # Lines: The lines of the interaction box used for highlights. # Markers: The the outlines for each point used for highlights. # Markers: The actual markers of each point. node = Compound([Markers(), Markers(), Line()]) super().__init__(layer, node) self.layer.events.symbol.connect(lambda e: self._on_data_change()) self.layer.events.edge_width.connect(lambda e: self._on_data_change()) self.layer.events.edge_color.connect(lambda e: self._on_data_change()) self.layer.events.face_color.connect(lambda e: self._on_data_change()) self.layer.events.highlight.connect( lambda e: self._on_highlight_change()) self._on_display_change() self._on_data_change()
def __init__(self, layer): # Create a compound visual with the following four subvisuals: # Markers: corresponding to the vertices of the interaction box or the # shapes that are used for highlights. # Lines: The lines of the interaction box used for highlights. # Mesh: The mesh of the outlines for each shape used for highlights. # Mesh: The actual meshes of the shape faces and edges node = Compound([Mesh(), Mesh(), Line(), Markers()]) super().__init__(layer, node) self.layer.events.edge_width.connect(self._on_data_change) self.layer.events.edge_color.connect(self._on_data_change) self.layer.events.face_color.connect(self._on_data_change) self.layer.events.highlight.connect(self._on_highlight_change) self._reset_base() self._on_data_change() self._on_highlight_change()
def attach(self, viewer, view, canvas, parent=None, order=0): super().attach(viewer, view, canvas, parent, order) self._update_line_data() self.node = Compound( [Line(connect='segments', method='gl', width=4)], parent=parent, ) self.node.transform = STTransform() self.node.order = order self._nodes = [self.node] canvas.connect(self.on_mouse_press) canvas.connect(self.on_mouse_move) canvas.connect(self.on_mouse_release) self._viewer.camera.events.zoom.connect(self._on_zoom_change) self._viewer.dims.events.ndisplay.connect(self._on_data_change) self._on_data_change(None)
def __init__(self, layer): # Create a compound visual with the following four subvisuals: # Lines: The lines of the interaction box used for highlights. # Markers: The the outlines for each point used for highlights. # Markers: The actual markers of each point. node = Compound([Markers(), Markers(), Line(), Text()]) super().__init__(layer, node) self.layer.events.symbol.connect(self._on_data_change) self.layer.events.edge_width.connect(self._on_data_change) self.layer.events.edge_color.connect(self._on_data_change) self.layer._edge.events.colors.connect(self._on_data_change) self.layer._edge.events.color_properties.connect(self._on_data_change) self.layer.events.face_color.connect(self._on_data_change) self.layer._face.events.colors.connect(self._on_data_change) self.layer._face.events.color_properties.connect(self._on_data_change) self.layer.text._connect_update_events(self._on_text_change, self._on_blending_change) self.layer.events.highlight.connect(self._on_highlight_change) self._on_data_change() self._reset_base()
def chromaticity_diagram_construction_visual( cmfs='CIE 1931 2 Degree Standard Observer', width=2.0, method='gl', parent=None): """ Returns a :class:`vispy.scene.visuals.Node` class instance representing the chromaticity diagram construction with the spectral locus. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used to draw the spectral locus. width : numeric, optional Line width. method : unicode, optional **{'gl', 'agg'}**, Line drawing method. parent : Node, optional Parent of the spectral locus visual in the `SceneGraph`. Returns ------- Node Chromaticity diagram construction visual. """ from colour_analysis.visuals import Primitive node = Node(parent=parent) simplex_p = np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]) simplex_f = np.array([(0, 1, 2)]) simplex_c = np.array([(1, 1, 1), (1, 1, 1), (1, 1, 1)]) Primitive( simplex_p, simplex_f, uniform_opacity=0.5, vertex_colours=simplex_c, parent=node) simplex_f = np.array([(0, 1, 2), (1, 2, 0), (2, 0, 1)]) Primitive( simplex_p, simplex_f, uniform_opacity=1.0, vertex_colours=simplex_c, wireframe=True, parent=node) lines = [] for XYZ in first_item(filter_cmfs(cmfs).values()).values: lines.append(XYZ * 1.75) lines.append((0, 0, 0)) lines = np.array(lines) Line(lines, (0, 0, 0), width=width, method=method, parent=node) return node
def __init__( self, coords, *, symbol='o', size=10, edge_width=1, edge_color='black', face_color='white', n_dimensional=False, name=None, ): # Create a compound visual with the following four subvisuals: # Lines: The lines of the interaction box used for highlights. # Markers: The the outlines for each point used for highlights. # Markers: The actual markers of each point. visual = Compound([Line(), Markers(), Markers()]) super().__init__(visual, name) self.events.add( mode=Event, size=Event, face_color=Event, edge_color=Event, symbol=Event, n_dimensional=Event, ) self._colors = get_color_names() # Freeze refreshes with self.freeze_refresh(): # Save the point coordinates self._data = coords # Save the point style params self.symbol = symbol self.n_dimensional = n_dimensional self.edge_width = edge_width self.sizes = size self.edge_colors = list( itertools.islice(ensure_iterable(edge_color, color=True), 0, len(self.data))) self.face_colors = list( itertools.islice(ensure_iterable(face_color, color=True), 0, len(self.data))) # The following point properties are for the new points that will # be added. For any given property, if a list is passed to the # constructor so each point gets its own value then the default # value is used when adding new points if np.isscalar(size): self._size = size else: self._size = 10 if type(edge_color) is str: self._edge_color = edge_color else: self._edge_color = 'black' if type(face_color) is str: self._face_color = face_color else: self._face_color = 'white' # Indices of selected points self._selected_data = [] self._selected_data_stored = [] self._selected_data_history = [] # Indices of selected points within the currently viewed slice self._selected_view = [] # Index of hovered point self._hover_point = None self._hover_point_stored = None self._selected_box = None self._mode = Mode.PAN_ZOOM self._mode_history = self._mode self._status = self.mode self._drag_start = None # Nx2 array of points in the currently viewed slice self._data_view = np.empty((0, 2)) # Sizes of points in the currently viewed slice self._sizes_view = 0 # Full data indices of points located in the currently viewed slice self._indices_view = [] self._drag_box = None self._drag_box_stored = None self._is_selecting = False self._clipboard = {} # update flags self._need_display_update = False self._need_visual_update = False # Re intitialize indices depending on image dims self._indices = (0, ) * (self.ndim - 2) + ( slice(None, None, None), slice(None, None, None), ) # Trigger generation of view slice and thumbnail self._set_view_slice()
def __init__(self): super().__init__([Mesh(), Mesh(), Line(), Markers(), Text()])
class Animate: def __init__(self, data, c=None, labels=None, display=Scatter, tour_path=grand_tour(), start=None, parent=None, draw_boundary=None): self.curr_aps = 0 self.base_aps = 1 self.framerate = 144 self.draw_boundary = draw_boundary self.scale = 1000 self.s = MinMaxScaler(feature_range=(-1, 1)) self.tour = Tour(data, tour_path, start) self.step = self.tour.proj * self.scale self.data = self.s.fit_transform(data) self.mat = np.matmul(self.data, self.step, dtype=np.float32) self.display = Scatter(self.mat, self.step, c=c, labels=labels, parent=parent) self.wires = get_wires(p=data.shape[1]) self.vertices = get_vertices(p=data.shape[1]) self.res = np.matmul(self.vertices, self.step, dtype=np.float32) if self.draw_boundary == "hull": self.hull_frame = get_hull(self.res, self.wires) self.frame = Line(pos=self.hull_frame, method="gl", connect="segments", parent=parent, color="black") elif self.draw_boundary == "wire": res = get_hypercube(self.res, self.wires) self.frame = Line(pos=res, method="gl", connect="segments", parent=parent, color="black") def on_timer(self, event): if self.curr_aps != 0: self.step = self.tour.interpolate( self.curr_aps / self.framerate) * self.scale self.mat = np.matmul(self.data, self.step, dtype=np.float32) self.display.set_data(self.mat, self.step) self.display.update() if self.draw_boundary == "hull": self.res = np.matmul(self.vertices, self.step, dtype=np.float32) self.hull_frame = get_hull(self.res, self.wires) self.frame.set_data(pos=self.hull_frame, connect="segments", color="black") elif self.draw_boundary == "wire": self.res = np.matmul(self.vertices, self.step, dtype=np.float32) res = get_hypercube(self.res, self.wires) self.frame.set_data(pos=res, connect="segments", color="black") def on_key_press(self, event): if event.key == "=": self.curr_aps = self.base_aps if event.key == "-": self.curr_aps = -self.base_aps if event.key == "F8": print(self.step / self.scale) np.savetxt("matrix.csv", self.step / self.scale, delimiter=",") print("Projection saved to: matrix.csv") def on_key_release(self, event): if event.key == "-" or event.key == "=": self.curr_aps = 0 def on_mouse_press(self, event): # print(event.pos) pass
def init_visual(self, view): """Initialize the object visual.""" self.visual = Line(pos = sphere_pt * self.rad + self.pos, color=self.color) view.add(self.visual)
def spectral_locus_visual(reference_colourspace='CIE xyY', cmfs='CIE 1931 2 Degree Standard Observer', width=2.0, uniform_colour=None, uniform_opacity=1.0, method='gl', parent=None): """ Returns a :class:`vispy.scene.visuals.Line` class instance representing the spectral locus. Parameters ---------- reference_colourspace : unicode, optional **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW', 'IPT', 'Hunter Lab', 'Hunter Rdab'}**, Reference colourspace to use for colour conversions / transformations. cmfs : unicode, optional Standard observer colour matching functions used to draw the spectral locus. width : numeric, optional Line width. uniform_colour : array_like, optional Uniform symbol colour. uniform_opacity : numeric, optional Uniform symbol opacity. method : unicode, optional **{'gl', 'agg'}**, Line drawing method. parent : Node, optional Parent of the spectral locus visual in the `SceneGraph`. Returns ------- Line Spectral locus visual. """ cmfs = first_item(filter_cmfs(cmfs).values()) XYZ = cmfs.values XYZ = np.vstack([XYZ, XYZ[0, ...]]) illuminant = DEFAULT_PLOTTING_ILLUMINANT points = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ, illuminant, reference_colourspace), reference_colourspace) points[np.isnan(points)] = 0 if uniform_colour is None: RGB = normalise_maximum(XYZ_to_sRGB(XYZ, illuminant), axis=-1) RGB = np.hstack([ RGB, np.full((RGB.shape[0], 1), uniform_opacity, DEFAULT_FLOAT_DTYPE) ]) else: RGB = ColorArray(uniform_colour, alpha=uniform_opacity).rgba line = Line(points, np.clip(RGB, 0, 1), width=width, method=method, parent=parent) return line
def __init__(self, viewer, parent=None, order=0): self._viewer = viewer self._data = np.array([ [0, 0, -1], [1, 0, -1], [0, -5, -1], [0, 5, -1], [1, -5, -1], [1, 5, -1], ]) self._target_length = 150 self._scale = 1 self._quantity = None self._unit_reg = None self.line_node = Line(connect='segments', method='gl', parent=parent, width=3) self.line_node.order = order + 1 self.line_node.transform = STTransform() # In order for the text and box to always appear centered on the scale # bar, the text and rect nodes should use the line node as the parent. self.text_node = Text(pos=[0.5, -1], parent=self.line_node) self.text_node.order = order + 1 self.text_node.transform = STTransform() self.text_node.font_size = 10 self.text_node.anchors = ("center", "center") self.text_node.text = f"{1}px" self.rect_node = Rectangle( center=[0.5, 0.5], width=1.1, height=36, color=self._viewer.scale_bar.box_color, parent=self.line_node, ) self.rect_node.order = order self.rect_node.transform = STTransform() # the two canvas are not the same object, better be safe. self.rect_node.canvas._backend.destroyed.connect(self._set_canvas_none) self.line_node.canvas._backend.destroyed.connect(self._set_canvas_none) self.text_node.canvas._backend.destroyed.connect(self._set_canvas_none) assert self.rect_node.canvas is self.line_node.canvas assert self.line_node.canvas is self.text_node.canvas # End Note self._viewer.events.theme.connect(self._on_data_change) self._viewer.scale_bar.events.visible.connect(self._on_visible_change) self._viewer.scale_bar.events.colored.connect(self._on_data_change) self._viewer.scale_bar.events.ticks.connect(self._on_data_change) self._viewer.scale_bar.events.box_color.connect(self._on_data_change) self._viewer.scale_bar.events.color.connect(self._on_data_change) self._viewer.scale_bar.events.position.connect( self._on_position_change) self._viewer.camera.events.zoom.connect(self._on_zoom_change) self._viewer.scale_bar.events.font_size.connect(self._on_text_change) self._viewer.scale_bar.events.unit.connect(self._on_dimension_change) self._viewer.scale_bar.events.box.connect(self._on_visible_change) self._on_visible_change() self._on_data_change() self._on_dimension_change() self._on_position_change()
def debug(self, measurements, file_path, add_geodesic): # Model object model = mesh_lib.Model(file_path) model_point_coordinates = model.get_coords() canvas = scene.SceneCanvas(keys='interactive') view = canvas.central_widget.add_view() # all model - GREEN points = Markers(parent=view.scene) points.set_data( pos=model_point_coordinates, edge_color=None, face_color=(0, 1, 0, .3), size=5 ) data_list = [] for m in measurements: # measurements in config file # parsing key vertexes and description text point_1 = int(m[1]) + 1 point_2 = int(m[2]) + 1 point_3 = int(m[3]) + 1 text = " ".join(m[4:]) # coordinates of key vertexes key_coords = model.get_coords((point_1, point_2, point_3)) # plane that goes through all three key vertexes plane = mesh_lib.get_plane(key_coords) # key vertexes WHITE points = Markers() points.set_data( pos=key_coords, edge_color=None, face_color=(1, 1, 1, 1), size=5 ) # "C" - circumference if m[0] == "C": # 3 segments of path (indexes) p_1 = model.get_path(point_1, point_2) p_2 = model.get_path(point_2, point_3) p_3 = model.get_path(point_3, point_1) # full path path = p_1 + p_2[1:] + p_3[1:] # "L" - Length if m[0] == "L": # 2 segments of path (indexes) p_1 = model.get_path(point_1, point_2) p_2 = model.get_path(point_2, point_3) # full path path = p_1 + p_2[1:] # geodesic geodesic_coordinates = model.get_coords(path) geodesic_length = mesh_lib.get_length(geodesic_coordinates) print("{0}:".format(text)) print( " Geodesic distance: {0} cm".format( round(100 * geodesic_length, 3) ) ) if add_geodesic: # if debug_full # geodesic line - RED line = Line(parent=view.scene) line.set_data( pos=geodesic_coordinates, color=(1, 0, 0, 1) ) # approximated flattened_coordinates = mesh_lib.get_projections(plane, geodesic_coordinates) flattened_length = mesh_lib.get_length(flattened_coordinates) print( " Approximated distance: {0} cm".format( round(100 * flattened_length, 3) ) ) data_list.append(geodesic_length) data_list.append(flattened_length) # flattened line - BLUE line = Line(parent=view.scene) line.set_data( pos=flattened_coordinates, color=(0, 0, 1, 1) ) view.camera = 'turntable' view.camera.fov = 45 view.camera.distance = 3 axis = XYZAxis(parent=view.scene) final_result = {"canvas":canvas,"data":data_list} return final_result
def init_visual(self, view): """Initialize the object visual.""" self.trace = np.repeat(self.pos, self.tail_steps).reshape((3,self.tail_steps)).T pos = np.concatenate([sphere_pt * self.rad + self.pos, self.trace]) self.visual = Line(pos = pos, color=self.color) view.add(self.visual)
class VispyScaleBarVisual: """Scale bar in world coordinates. """ def __init__(self, scale_bar, parent=None, order=0): self._data = np.array([ [0, 0, -1], [1, 0, -1], [0, -5, -1], [0, 5, -1], [1, -5, -1], [1, 5, -1], ]) self._default_color = np.array([1, 0, 1, 1]) self._target_length = 100 self._scale = 1 self.scale_bar = scale_bar self.node = Line(connect='segments', method='gl', parent=parent, width=3) self.node.order = order self.node.transform = STTransform() self.text_node = Text(pos=[0, 0], parent=parent) self.text_node.order = order self.text_node.transform = STTransform() self.text_node.font_size = 10 self.text_node.anchors = ('center', 'center') self.text_node.text = f'{1}' self.scale_bar.events.visible.connect(self._on_visible_change) self.scale_bar.events.colored.connect(self._on_data_change) self.scale_bar.events.ticks.connect(self._on_data_change) self.scale_bar.events.position.connect(self._on_position_change) self._on_visible_change(None) self._on_data_change(None) self._on_position_change(None) def update_scale(self, scale): """Update scale bar length based on canvas2world scale. Parameters ---------- scale : float Scale going from canvas pixels to world coorindates. """ # If scale has not changed, do not redraw if abs(np.log10(self._scale) - np.log10(scale)) < 1e-4: return self._scale = scale scale_canvas2world = self._scale target_canvas_pixels = self._target_length target_world_pixels = scale_canvas2world * target_canvas_pixels # Round scalebar to nearest factor of 1, 2, 5, 10 in world pixels on a log scale resolutions = [1, 2, 5, 10] log_target = np.log10(target_world_pixels) mult_ind = np.argmin( np.abs(np.subtract(np.log10(resolutions), log_target % 1))) power_val = np.floor(log_target) target_world_pixels_rounded = resolutions[mult_ind] * np.power( 10, power_val) # Convert back to canvas pixels to get actual length of scale bar target_canvas_pixels_rounded = (target_world_pixels_rounded / scale_canvas2world) scale = target_canvas_pixels_rounded if self.scale_bar._position in [ Position.TOP_RIGHT, Position.BOTTOM_RIGHT, ]: sign = -1 else: sign = 1 # Update scalebar and text self.node.transform.scale = [sign * scale, 1, 1, 1] self.text_node.text = f'{target_world_pixels_rounded:.4g}' def _on_data_change(self, event): """Change color and data of scale bar.""" if self.scale_bar.colored: color = self._default_color else: color = np.subtract(1, self.scale_bar.background_color)[:3] if self.scale_bar.ticks: data = self._data else: data = self._data[:2] self.node.set_data(data, color) self.text_node.color = color def _on_visible_change(self, event): """Change visibiliy of scale bar.""" self.node.visible = self.scale_bar.visible self.text_node.visible = self.scale_bar.visible def _on_position_change(self, event): """Change position of scale bar.""" if self.scale_bar._position == Position.TOP_LEFT: sign = 1 self.node.transform.translate = [66, 14, 0, 0] self.text_node.transform.translate = [33, 16, 0, 0] elif self.scale_bar._position == Position.TOP_RIGHT: sign = -1 canvas_size = list(self.node.canvas.size) self.node.transform.translate = [canvas_size[0] - 66, 14, 0, 0] self.text_node.transform.translate = [ canvas_size[0] - 33, 16, 0, 0, ] elif self.scale_bar._position == Position.BOTTOM_RIGHT: sign = -1 canvas_size = list(self.node.canvas.size) self.node.transform.translate = [ canvas_size[0] - 66, canvas_size[1] - 16, 0, 0, ] self.text_node.transform.translate = [ canvas_size[0] - 33, canvas_size[1] - 14, 0, 0, ] elif self.scale_bar._position == Position.BOTTOM_LEFT: sign = 1 canvas_size = list(self.node.canvas.size) self.node.transform.translate = [66, canvas_size[1] - 16, 0, 0] self.text_node.transform.translate = [ 33, canvas_size[1] - 14, 0, 0, ] else: raise ValueError(f'Position {self.scale_bar.position}' ' not recognized.') scale = abs(self.node.transform.scale[0]) self.node.transform.scale = [sign * scale, 1, 1, 1]
class VispyScaleBarVisual: """Scale bar in world coordinates.""" def __init__(self, viewer, parent=None, order=0): self._viewer = viewer self._data = np.array([ [0, 0, -1], [1, 0, -1], [0, -5, -1], [0, 5, -1], [1, -5, -1], [1, 5, -1], ]) self._default_color = np.array([1, 0, 1, 1]) self._target_length = 150 self._scale = 1 self._quantity = None self._unit_reg = None self.node = Line(connect='segments', method='gl', parent=parent, width=3) self.node.order = order self.node.transform = STTransform() # In order for the text to always appear centered on the scale bar, # the text node should use the line node as the parent. self.text_node = Text(pos=[0.5, -1], parent=self.node) self.text_node.order = order self.text_node.transform = STTransform() self.text_node.font_size = 10 self.text_node.anchors = ("center", "center") self.text_node.text = f"{1}px" # Note: # There are issues on MacOS + GitHub action about destroyed # C/C++ object during test if those don't get disconnected. def set_none(): self.node._set_canvas(None) self.text_node._set_canvas(None) # the two canvas are not the same object, better be safe. self.node.canvas._backend.destroyed.connect(set_none) self.text_node.canvas._backend.destroyed.connect(set_none) assert self.node.canvas is self.text_node.canvas # End Note self._viewer.events.theme.connect(self._on_data_change) self._viewer.scale_bar.events.visible.connect(self._on_visible_change) self._viewer.scale_bar.events.colored.connect(self._on_data_change) self._viewer.scale_bar.events.ticks.connect(self._on_data_change) self._viewer.scale_bar.events.position.connect( self._on_position_change) self._viewer.camera.events.zoom.connect(self._on_zoom_change) self._viewer.scale_bar.events.font_size.connect(self._on_text_change) self._viewer.scale_bar.events.unit.connect(self._on_dimension_change) self._on_visible_change(None) self._on_data_change(None) self._on_dimension_change(None) self._on_position_change(None) @property def unit_registry(self): """Get unit registry. Rather than instantiating UnitRegistry earlier on, it is instantiated only when it is needed. The reason for this is that importing `pint` at module level can be time consuming. Notes ----- https://github.com/napari/napari/pull/2617#issuecomment-827716325 https://github.com/napari/napari/pull/2325 """ if self._unit_reg is None: self._unit_reg = get_unit_registry() return self._unit_reg def _on_dimension_change(self, event): """Update dimension.""" if not self._viewer.scale_bar.visible and self._unit_reg is None: return unit = self._viewer.scale_bar.unit self._quantity = self.unit_registry(unit) self._on_zoom_change(None, True) def _calculate_best_length(self, desired_length: float): """Calculate new quantity based on the pixel length of the bar. Parameters ---------- desired_length : float Desired length of the scale bar in world size. Returns ------- new_length : float New length of the scale bar in world size based on the preferred scale bar value. new_quantity : pint.Quantity New quantity with abbreviated base unit. """ current_quantity = self._quantity * desired_length # convert the value to compact representation new_quantity = current_quantity.to_compact() # calculate the scaling factor taking into account any conversion # that might have occurred (e.g. um -> cm) factor = current_quantity / new_quantity # select value closest to one of our preferred values index = bisect.bisect_left(PREFERRED_VALUES, new_quantity.magnitude) if index > 0: # When we get the lowest index of the list, removing -1 will # return the last index. index -= 1 new_value = PREFERRED_VALUES[index] # get the new pixel length utilizing the user-specified units new_length = ((new_value * factor) / self._quantity.magnitude).magnitude new_quantity = new_value * new_quantity.units return new_length, new_quantity def _on_zoom_change(self, event, force: bool = False): """Update axes length based on zoom scale.""" if not self._viewer.scale_bar.visible: return # If scale has not changed, do not redraw scale = 1 / self._viewer.camera.zoom if abs(np.log10(self._scale) - np.log10(scale)) < 1e-4 and not force: return self._scale = scale scale_canvas2world = self._scale target_canvas_pixels = self._target_length # convert desired length to world size target_world_pixels = scale_canvas2world * target_canvas_pixels # calculate the desired length as well as update the value and units target_world_pixels_rounded, new_dim = self._calculate_best_length( target_world_pixels) target_canvas_pixels_rounded = (target_world_pixels_rounded / scale_canvas2world) scale = target_canvas_pixels_rounded sign = (-1 if self._viewer.scale_bar.position in [Position.TOP_RIGHT, Position.BOTTOM_RIGHT] else 1) # Update scalebar and text self.node.transform.scale = [sign * scale, 1, 1, 1] self.text_node.text = f'{new_dim:~}' def _on_data_change(self, event): """Change color and data of scale bar.""" if self._viewer.scale_bar.colored: color = self._default_color else: background_color = get_theme(self._viewer.theme)['canvas'] background_color = transform_color(background_color)[0] color = np.subtract(1, background_color) color[-1] = background_color[-1] if self._viewer.scale_bar.ticks: data = self._data else: data = self._data[:2] self.node.set_data(data, color) self.text_node.color = color def _on_visible_change(self, event): """Change visibility of scale bar.""" self.node.visible = self._viewer.scale_bar.visible self.text_node.visible = self._viewer.scale_bar.visible # update unit if scale bar is visible and quantity # has not been specified yet or current unit is not # equivalent if self._viewer.scale_bar.visible and ( self._quantity is None or self._quantity.units != self._viewer.scale_bar.unit): self._quantity = self.unit_registry(self._viewer.scale_bar.unit) # only force zoom update if the scale bar is visible self._on_zoom_change(None, self._viewer.scale_bar.visible) def _on_text_change(self, event): """Update text information""" self.text_node.font_size = self._viewer.scale_bar.font_size def _on_position_change(self, event): """Change position of scale bar.""" position = self._viewer.scale_bar.position x_bar_offset, y_bar_offset = 10, 30 canvas_size = list(self.node.canvas.size) if position == Position.TOP_LEFT: sign = 1 bar_transform = [x_bar_offset, 10, 0, 0] elif position == Position.TOP_RIGHT: sign = -1 bar_transform = [canvas_size[0] - x_bar_offset, 10, 0, 0] elif position == Position.BOTTOM_RIGHT: sign = -1 bar_transform = [ canvas_size[0] - x_bar_offset, canvas_size[1] - y_bar_offset, 0, 0, ] elif position == Position.BOTTOM_LEFT: sign = 1 bar_transform = [x_bar_offset, canvas_size[1] - 30, 0, 0] else: raise ValueError( trans._( 'Position {position} not recognized.', deferred=True, position=self._viewer.scale_bar.position, )) self.node.transform.translate = bar_transform scale = abs(self.node.transform.scale[0]) self.node.transform.scale = [sign * scale, 1, 1, 1] self.text_node.transform.translate = (0, 20, 0, 0)
def __init__(self): self.reset() self.line = Line( connect='segments', color=GRID_COLOR, width=GRID_WIDTH ) self.line.order = 10
def __init__(self, axes, dims, parent=None, order=0): self.axes = axes self.dims = dims # note order is z, y, x self._default_data = np.array( [[0, 0, 0], [0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 0, 0], [1, 0, 0]] ) self._default_color = np.concatenate( [[[0, 1, 1, 1]] * 2, [[1, 1, 0, 1]] * 2, [[1, 0, 1, 1]] * 2], axis=0, ) # note order is z, y, x self._dashed_data = np.concatenate( [ [[0, 0, 0], [0, 0, 1]], make_dashed_line(4, axis=1), make_dashed_line(8, axis=0), ], axis=0, ) self._dashed_color = np.concatenate( [ [[0, 1, 1, 1]] * 2, [[1, 1, 0, 1]] * 4 * 2, [[1, 0, 1, 1]] * 8 * 2, ], axis=0, ) vertices = np.empty((0, 3)) faces = np.empty((0, 3)) # note order is z, y, x for axis in range(3): v, f = make_arrow_head(self._NUM_SEGMENTS_ARROWHEAD, 2 - axis) faces = np.concatenate([faces, f + len(vertices)], axis=0) vertices = np.concatenate([vertices, v], axis=0) self._default_arrow_vertices = vertices self._default_arrow_faces = faces.astype(int) self._default_arrow_color = np.concatenate( [ [[0, 1, 1, 1]] * self._NUM_SEGMENTS_ARROWHEAD, [[1, 1, 0, 1]] * self._NUM_SEGMENTS_ARROWHEAD, [[1, 0, 1, 1]] * self._NUM_SEGMENTS_ARROWHEAD, ], axis=0, ) self._target_length = 80 self.node = Compound( [Line(connect='segments', method='gl', width=3), Mesh()], parent=parent, ) self.node.transform = STTransform() self.node.order = order self.axes.events.visible.connect(self._on_visible_change) self.axes.events.colored.connect(self._on_data_change) self.axes.events.dashed.connect(self._on_data_change) self.axes.events.arrows.connect(self._on_data_change) self.dims.events.order.connect(self._on_data_change) self._on_visible_change(None) self._on_data_change(None) self._scale = 1
def __init__(self): self.clamp_filter = ClampSizeFilter() super().__init__([Markers(), Markers(), Line(), Text()]) self.attach(self.clamp_filter) self.scaling = True
def __init__(self): super().__init__([Markers(), Markers(), Line(), Text()]) self.scaling = True
def __init__(self, viewer, parent=None, order=0): self._viewer = viewer self._scale = 1 # Target axes length in canvas pixels self._target_length = 80 # CMYRGB for 6 axes data in x, y, z, ... ordering self._default_color = [ [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], ] # Text offset from line end position self._text_offsets = 0.1 * np.array([1, 1, 1]) # note order is x, y, z for VisPy self._line_data2D = np.array([[0, 0, 0], [1, 0, 0], [0, 0, 0], [0, 1, 0]]) self._line_data3D = np.array([[0, 0, 0], [1, 0, 0], [0, 0, 0], [0, 1, 0], [0, 0, 0], [0, 0, 1]]) # note order is x, y, z for VisPy self._dashed_line_data2D = np.concatenate( [[[1, 0, 0], [0, 0, 0]], make_dashed_line(4, axis=1)], axis=0, ) self._dashed_line_data3D = np.concatenate( [ [[1, 0, 0], [0, 0, 0]], make_dashed_line(4, axis=1), make_dashed_line(8, axis=2), ], axis=0, ) # note order is x, y, z for VisPy vertices = np.empty((0, 3)) faces = np.empty((0, 3)) for axis in range(2): v, f = make_arrow_head(self._NUM_SEGMENTS_ARROWHEAD, axis) faces = np.concatenate([faces, f + len(vertices)], axis=0) vertices = np.concatenate([vertices, v], axis=0) self._default_arrow_vertices2D = vertices self._default_arrow_faces2D = faces.astype(int) vertices = np.empty((0, 3)) faces = np.empty((0, 3)) for axis in range(3): v, f = make_arrow_head(self._NUM_SEGMENTS_ARROWHEAD, axis) faces = np.concatenate([faces, f + len(vertices)], axis=0) vertices = np.concatenate([vertices, v], axis=0) self._default_arrow_vertices3D = vertices self._default_arrow_faces3D = faces.astype(int) self.node = Compound( [Line(connect='segments', method='gl', width=3), Mesh(), Text()], parent=parent, ) self.node.transform = STTransform() self.node.order = order # Add a text node to display axes labels self.text_node = self.node._subvisuals[2] self.text_node.font_size = 10 self.text_node.anchors = ('center', 'center') self.text_node.text = f'{1}' self._viewer.events.theme.connect(self._on_data_change) self._viewer.axes.events.visible.connect(self._on_visible_change) self._viewer.axes.events.colored.connect(self._on_data_change) self._viewer.axes.events.dashed.connect(self._on_data_change) self._viewer.axes.events.labels.connect(self._on_data_change) self._viewer.axes.events.arrows.connect(self._on_data_change) self._viewer.dims.events.order.connect(self._on_data_change) self._viewer.dims.events.ndisplay.connect(self._on_data_change) self._viewer.dims.events.axis_labels.connect(self._on_data_change) self._viewer.camera.events.zoom.connect(self._on_zoom_change) self._on_visible_change(None) self._on_data_change(None)
class Bubble2: """Class containg a n number of bubbles. It uses vispy to visualization.""" def __init__(self, position, velocity, boundaries = None, radius = None, color=(1.0, 1.0, 1.0, 1.0)): self.n = position.shape[0] self.pos = position self.vel = velocity self.color = color if radius is not None: self.rad = radius else: self.rad = np.zeros(self.n) + 0.1 self.bound = None self.sizexyz = [None] * 3 if boundaries is not None: self.set_bound(boundaries) self.visual = None def set_bound(self, boundaries): """Updates the boundaries.""" self.bound = boundaries self.sizexyz = np.abs(boundaries[:,1] - boundaries[:,0]) def step(self, time_step): """Calculate the new positions and speeds for all bubbles.""" despl = self.vel * time_step self.pos = self.pos + despl if self.sizexyz[2] is not None: offbound = np.where(self.pos[:,2] > self.bound[2,1]) off_n = offbound[0].size self.pos[offbound,0] = (self.sizexyz[0]) * np.random.rand(off_n) + self.bound[0,0] self.pos[offbound,1] = (self.sizexyz[1]) * np.random.rand(off_n) + self.bound[1,0] self.pos[offbound,2] = self.bound[2,0] self.rad[offbound] = 0.01 self.vel[offbound,2] = 0.0 on_bottom = np.where(self.pos[:,2] == self.bound[2,0]) self.rad[on_bottom] = self.rad[on_bottom] + 0.02 vel_free = self.vel[on_bottom,2][0] rad_free = self.rad[on_bottom] free = np.where(rad_free + np.random.rand(on_bottom[0].size) / 2 > 0.4) vel_free[free] = vel_free[free] + rad_free[free] self.vel[on_bottom,2] = vel_free not_on_bottom = np.where(self.pos[:,2] > self.bound[2,0]) self.vel[not_on_bottom,2] = self.vel[not_on_bottom,2] + self.rad[not_on_bottom] self.update_visual() def init_visual(self, view): """Initialize the object visual.""" num_seg = sphere_pt.shape[0] all_seg = np.zeros((num_seg * self.n, 3)) for i in range(self.n): all_seg[i * num_seg: (i + 1) * num_seg] = sphere_pt * self.rad[i] + self.pos[i,:] self.visual = Line(pos = all_seg, color=self.color, connect='segments') view.add(self.visual) def update_visual(self): """Updates the object visual.""" num_seg = sphere_pt.shape[0] all_seg = np.zeros((num_seg * self.n, 3)) for i in range(self.n): all_seg[i * num_seg: (i + 1) * num_seg] = sphere_pt * self.rad[i] + self.pos[i,:] self.visual.set_data(pos = all_seg) def shake(self): """Loose all the bubbles from the bottom.""" if self.sizexyz[2] is not None: self.pos[:,2] = self.pos[:,2] + 0.001