Skip to content

Basic Points#

Interactive points example demonstrating ColorModel subclasses and scaling modes.

This example shows: - Per-vertex coloring with VertexColors (each point gets a different color) - Uniform coloring with UniformColor (all points same color) - Fixed vs. scene-based point scaling modes - Interactive color swapping on mouse hover (face and edge colors swap)

The points start with per-vertex face colors (red, green, blue, yellow) and a white uniform edge. When the mouse hovers over any point, the colors invert: faces become white (uniform) and edges become colored (per-vertex).

Scaling modes: - "fixed": Point size in pixels, stays constant when zooming - "scene": Point size in world-space units, scales when zooming

Screenshot of Basic Points

import cmap
import numpy as np

import scenex as snx
from scenex.app.events import Event, MouseMoveEvent
from scenex.utils import projections

# Here is our points data
vertices = np.array(
    [
        [0, 0, 0],
        [0, 1, 0],
        [1, 0, 0],
        [1, 1, 0],
    ]
)
colors = [
    cmap.Color("red"),
    cmap.Color("green"),
    cmap.Color("blue"),
    cmap.Color("yellow"),
]
# Scenex provides a few different modes for point sizing.
# "fixed" scaling means the point size is defined in screen space (pixels),
# so it remains constant (fixed) as you zoom in and out.
points = snx.Points(
    name="point",
    vertices=vertices,
    size=20,  # Pixel diameter
    edge_width=10,
    scaling="fixed",
    face_color=snx.VertexColors(color=colors),
    edge_color=snx.UniformColor(color=cmap.Color("white")),
)
# "scene" scaling means the point size is defined in world space,
# so it varies as you zoom in and out.
# You can uncomment the following lines to try it out.
# points = snx.Points(
#     name="point",
#     vertices=vertices,
#     size=1,  # World-space diameter
#     edge_width=0,
#     scaling="scene",
#     face_color=snx.VertexColors(color=colors),
#     edge_color=snx.UniformColor(color=cmap.Color("white")),
# )


# Since ray-point intersections are computed in canvas space, we need view+canvas
view = snx.View(
    scene=snx.Scene(children=[points]), camera=snx.Camera(controller=snx.PanZoom())
)


def _on_view_event(event: Event) -> bool:
    if isinstance(event, MouseMoveEvent):
        if (ray := view.to_ray(event.pos)) is None:
            return False
        if ray.intersections(points):
            points.face_color = snx.UniformColor(color=cmap.Color("white"))
            points.edge_color = snx.VertexColors(color=colors)
        else:
            # Restore vertex colors
            points.face_color = snx.VertexColors(color=colors)
            points.edge_color = snx.UniformColor(color=cmap.Color("white"))
    return False


view.set_event_filter(_on_view_event)

# Show and position camera
snx.show(view)
view.camera.projection = projections.orthographic(2, 2, 1e5)
view.camera.transform = snx.Transform().translated((0.5, 0.5))
snx.run()