.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/scene/instanced_markers.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_scene_instanced_markers.py: Markers with Instanced Rendering ================================ Compare instanced and GL_POINTS rendering methods for Markers visual. This example shows how instanced rendering works around platform point size limits (many platforms limit GL_POINTS to 64px or smaller) and demonstrates the canvas_size_limits feature for constraining marker sizes during zoom/pan. Controls: * m: Toggle between 'points' and 'instanced' rendering methods * s: Cycle through marker sizes * c: Toggle canvas size clamping (min 10px, max 100px) * z: Toggle scaling mode: 'fixed' vs 'scene' (grows/shrinks with zoom) * l: Toggle spherical lighting (3D sphere effect) * k: Cycle through marker shapes (disc, arrow, ring, etc.) Notes: * you may not see a difference between methods on your platform - that's fine! * 'instanced' method should be the same across platforms (arbitrarily large markers) * Canvas size clamping keeps markers readable during zoom * Spherical lighting adds depth to markers with simulated 3D lighting * There may be lighting direction differences between methods (known issue) .. GENERATED FROM PYTHON SOURCE LINES 34-219 .. image-sg:: /gallery/scene/images/sphx_glr_instanced_markers_001.png :alt: instanced markers :srcset: /gallery/scene/images/sphx_glr_instanced_markers_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none method=instanced | symbol=disc | size=16px | clamp=off | scaling=fixed | lighting=off | .. code-block:: Python from itertools import cycle from vispy import scene, use from vispy.visuals.markers import symbol_shaders use(gl="gl+") marker_sizes = cycle([16, 32, 64, 96, 128, 256, 512]) scaling_modes = cycle(["fixed", "scene"]) marker_symbols = cycle(symbol_shaders.keys()) class Canvas(scene.SceneCanvas): def __init__(self): scene.SceneCanvas.__init__( self, keys="interactive", size=(512, 512), title="Instanced Markers Demo" ) self.unfreeze() self.view = self.central_widget.add_view() self.view.camera = scene.PanZoomCamera(rect=(0, 0, 512, 512), aspect=1.0) self.marker_positions, self.face_colors = _create_markers_pattern() self.method = "instanced" self.current_size = next(marker_sizes) self.current_symbol = next(marker_symbols) self.clamping_enabled = False self.scaling_mode = next(scaling_modes) self.spherical_enabled = False self.markers = scene.visuals.Markers( method=self.method, parent=self.view.scene, scaling=self.scaling_mode, spherical=self.spherical_enabled, ) self.freeze() self.markers.set_data( self.marker_positions, face_color=self.face_colors, edge_color="black", size=self.current_size, edge_width=2, symbol=self.current_symbol, ) self.view.bgcolor = "#2e3440" self.print_state() self.show() def print_state(self, changed=None): """Print current state with optional highlighting of what changed.""" clamp_str = ( f"{self.markers.canvas_size_limits}" if self.clamping_enabled else "off" ) parts = { 'method': f"method={self.method}", 'symbol': f"symbol={self.current_symbol}", 'size': f"size={self.current_size}px", 'clamp': f"clamp={clamp_str}", 'scaling': f"scaling={self.scaling_mode}", 'lighting': f"lighting={'on' if self.spherical_enabled else 'off'}", } # highlight the changed part in bold if changed and changed in parts: parts[changed] = f"\033[1m{parts[changed]}\033[0m" state_line = " | ".join(parts.values()) state_line = state_line.ljust(120) print(f"\r{state_line}", end="", flush=True) def on_key_press(self, event): if event.text == "m": self.method = "instanced" if self.method == "points" else "points" # recreate markers with new method, cannot change method on the fly self.markers.parent = None self.markers = scene.visuals.Markers( method=self.method, parent=self.view.scene ) self.markers.set_data( self.marker_positions, face_color=self.face_colors, edge_color="black", size=self.current_size, edge_width=2, symbol=self.current_symbol, ) self.markers.scaling = self.scaling_mode self.markers.spherical = self.spherical_enabled if self.clamping_enabled: self.markers.canvas_size_limits = (10, 100) self.print_state(changed='method') self.update() elif event.text == "s": self.current_size = next(marker_sizes) self.markers.set_data( self.marker_positions, face_color=self.face_colors, edge_color="black", size=self.current_size, edge_width=2, symbol=self.current_symbol, ) self.print_state(changed='size') self.update() elif event.text == "c": self.clamping_enabled = not self.clamping_enabled if self.clamping_enabled: self.markers.canvas_size_limits = (10, 100) else: self.markers.canvas_size_limits = None self.print_state(changed='clamp') self.update() elif event.text == "z": self.scaling_mode = next(scaling_modes) self.markers.scaling = self.scaling_mode self.print_state(changed='scaling') self.update() elif event.text == "l": self.spherical_enabled = not self.spherical_enabled self.markers.spherical = self.spherical_enabled self.print_state(changed='lighting') self.update() elif event.text == "k": self.current_symbol = next(marker_symbols) self.markers.symbol = self.current_symbol self.print_state(changed='symbol') self.update() def _create_markers_pattern(): import numpy as np # Create positions in a circle plus one in the center n = 12 angles = np.linspace(0, 2 * np.pi, n, endpoint=False) radius = 150 center = np.array([256, 256]) pos = np.column_stack( [center[0] + radius * np.cos(angles), center[1] + radius * np.sin(angles)] ).astype(np.float32) pos = np.vstack([pos, center]) colors = np.zeros((n + 1, 4), dtype=np.float32) for i in range(n): hue = i / n h = hue * 6 x = 1 - abs(h % 2 - 1) if h < 1: colors[i] = [1, x, 0, 1] elif h < 2: colors[i] = [x, 1, 0, 1] elif h < 3: colors[i] = [0, 1, x, 1] elif h < 4: colors[i] = [0, x, 1, 1] elif h < 5: colors[i] = [x, 0, 1, 1] else: colors[i] = [1, 0, x, 1] colors[-1] = [1, 1, 1, 1] return pos, colors if __name__ == "__main__": from vispy import app print(__doc__) canvas = Canvas() app.run() .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.744 seconds) .. _sphx_glr_download_gallery_scene_instanced_markers.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: instanced_markers.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: instanced_markers.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: instanced_markers.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_