def map_property( prop: np.ndarray, colormap: Colormap, contrast_limits: Union[None, Tuple[float, float]] = None, ) -> Tuple[np.ndarray, Tuple[float, float]]: """Apply a colormap to a property Parameters ---------- prop : np.ndarray The property to be colormapped colormap : vispy.color.Colormap The vispy colormap object to apply to the property contrast_limits: Union[None, Tuple[float, float]] The contrast limits for applying the colormap to the property. If a 2-tuple is provided, it should be provided as (lower_bound, upper_bound). If None is provided, the contrast limits will be set to (property.min(), property.max()). Default value is None. """ if contrast_limits is None: contrast_limits = (prop.min(), prop.max()) normalized_properties = np.interp(prop, contrast_limits, (0, 1)) mapped_properties = colormap.map(normalized_properties) return mapped_properties, contrast_limits
def test_colormap(name): np.random.seed(0) cmap = AVAILABLE_COLORMAPS[name] # Test can map random 0-1 values values = np.random.rand(50) colors = cmap.map(values) assert colors.shape == (len(values), 4) # Create vispy colormap and check current colormaps match vispy # colormap vispy_cmap = VispyColormap(*cmap) vispy_colors = vispy_cmap.map(values) np.testing.assert_almost_equal(colors, vispy_colors, decimal=6)
class Viewer3D(object): """ A class for displaying a 3D model. """ #%% scaling = 10 # VisPy rendering very poor when values < 1, so scale up __scene = None # Don't import VisPy unless and until actually needed __geometry = None __io = None __gloo = None #%% def __init__(self, background='#cfcfef', scaling=20, el_az=None): if Viewer3D.__scene is None: from vispy import scene, geometry, io, gloo Viewer3D.__scene = scene Viewer3D.__geometry = geometry Viewer3D.__io = io Viewer3D.__gloo = gloo # Available colormaps in Vispy: # autumn, blues, cool, greens, reds, spring, summer, fire, grays, hot, ice, winter, light_blues, # orange, viridis, coolwarm, PuGr, GrBu, GrBu_d, RdBu, cubehelix, single_hue, hsl, husl, diverging, RdYeBuCy from vispy.color import Colormap self.__cmap = Colormap(['blue', 'cyan', 'green', 'yellow', 'red']) if el_az is None: el = 30 az = 45 else: el, az = el_az self.__canvas = Viewer3D.__scene.SceneCanvas(keys='interactive', size=(1200, 900), show=True) # Set up a viewbox to display the cube with interactive arcball self.__view = self.__canvas.central_widget.add_view() self.__view.bgcolor = background self.__view.camera = Viewer3D.__scene.cameras.turntable.TurntableCamera( scale_factor=scaling, elevation=el, azimuth=az) self.__view.padding = 5 Viewer3D.__scene.visuals.XYZAxis(parent=self.__view.scene) self.__vertex = None self.__vcolor = None #%% def Run(self, smooth=True, save_as=None): if self.__vertex is not None: data = Viewer3D.__geometry.MeshData(vertices=self.__vertex, vertex_colors=self.__vcolor) if smooth: mesh = Viewer3D.__scene.visuals.Mesh(meshdata=data, shading='smooth', parent=self.__view.scene) else: mesh = Viewer3D.__scene.visuals.Mesh(meshdata=data, parent=self.__view.scene) if save_as is None: self.__canvas.app.run() else: image = self.__canvas.render() # sort-of works, but problematic Viewer3D.__io.write_png(save_as, image) #%% def Line(self, vertices, color=None): """ Draws a line in 3D Parameters ---------- vertices : numpy.ndarray Array of vertices (Nv,3) to draw line through color : [r,g,b,a] array Color to use for drawing line; optional [default: black] """ if color is None: color = 'black' Viewer3D.__scene.visuals.Line(pos=(vertices * Viewer3D.scaling), color=color, parent=self.__view.scene) #%% def Add(self, triangle, color, uniform=True): """ Adds a triangle to the 3D mesh Parameters ---------- triangle : numpy.ndarray Array of vertices (3,3) for triangle color : [[r,g,b,a],] array Array of one or three colors to use for displaying face """ if self.__vertex is None: self.__vertex = np.asarray([triangle]) * Viewer3D.scaling if len(color) == 1: self.__vcolor = np.zeros((1, 3, 4)) self.__vcolor[0, :] = color[0] else: self.__vcolor = np.asarray([color]) else: vcoord = np.asarray([triangle]) * Viewer3D.scaling if len(color) == 1: vcolor = np.zeros((1, 3, 4)) vcolor[0, :] = color[0] else: vcolor = np.asarray([color]) self.__vertex = np.append(self.__vertex, vcoord, axis=0) self.__vcolor = np.append(self.__vcolor, vcolor, axis=0) #%% def ColorFromValue(self, c): """ Converts a value in a range to a color Parameters ---------- c : numpy.ndarray Array of values to map to color Returns ------- color : [[r,g,b,a],] array mapped color """ return self.__cmap.map(c) #%% def ColorBar(self, description, c_min_max_str): """ Add a colorbar to the plot """ # Overlays a grid to position subviews & widgets: grid = self.__canvas.central_widget.add_grid(margin=10) if sys.platform == "darwin": # On OSX, positioning of text in colorbar is unhelpful; this hackery seems to make it look okay, however label = '\n\n ' + description else: label = description cbar = Viewer3D.__scene.widgets.ColorBarWidget(self.__cmap, 'left', clim=c_min_max_str, label=label, axis_ratio=0.075, padding=[0.5, 0.5], border_width=1) grid.add_widget(cbar, col=0) # which centers the colorbar unless we add something else to effectively nudge it to the left: view = grid.add_view(col=1, col_span=3) view.visible = False
galaxy_data = load_galaxy_data("../data/vollim_dr7_cbp_102709.fits") print("Galaxies: ", galaxy_data.shape) print("Voids: ", voids_tri_x.shape, voids_tri_y.shape, voids_tri_z.shape, voids_norm.shape, voids_id.shape) ################################################################################ ################################################################################ # Void coloring #------------------------------------------------------------------------------- num_voids = len(np.unique(voids_id)) cm = Colormap( ['#880000', '#EEEE00', "#008800", '#EE00EE', '#000088', '#EE00EE']) void_color_vals = cm.map(np.linspace(0, 1.0, num_voids)) print(void_color_vals.shape) void_colors = np.empty((num_voids, 4), dtype=np.float32) for idx in range(void_colors.shape[0]): void_id = idx #print(hole_group) void_colors[idx, :] = void_color_vals[void_id] ################################################################################ ################################################################################
print("Holes:", holes_xyz.shape, holes_radii.shape, holes_flags.shape) ################################################################################ # # VOID COLORING # ################################################################################ hole_IDs = np.unique(holes_flags) num_hole_groups = len(hole_IDs) cm = Colormap( ['#880000', '#EEEE00', "#008800", '#EE00EE', '#000088', '#EE00EE']) hole_color_vals = cm.map(np.linspace(0, 1.0, num_hole_groups)) print(hole_color_vals.shape) void_hole_colors = np.empty((holes_xyz.shape[0], 4), dtype=np.float32) for idx in range(void_hole_colors.shape[0]): hole_group = holes_flags[idx] #print(hole_group) void_hole_colors[idx, :] = hole_color_vals[ hole_group - 1] # uhg you used 1-based indexing WHY? :D ################################################################################