def test_set_stroke_handles_lists_of_color_objects(using_opengl_renderer): m = OpenGLVMobject() assert m.stroke_color.hex == "#fff" m.set_stroke([Color(PURE_BLUE), Color(PURE_GREEN), Color(PURE_RED)]) assert m.get_stroke_colors()[0].hex == "#00f" assert m.get_stroke_colors()[1].hex == "#0f0" assert m.get_stroke_colors()[2].hex == "#f00"
def test_set_stroke_handles_lists_of_strs(using_opengl_renderer): m = OpenGLVMobject() assert m.stroke_color.hex == "#fff" m.set_stroke([BLACK, BLUE, GREEN]) assert m.get_stroke_colors()[0] == Color(BLACK) assert m.get_stroke_colors()[1] == Color(BLUE) assert m.get_stroke_colors()[2] == Color(GREEN)
def test_set_stroke_color(using_opengl_renderer): m = OpenGLVMobject() assert m.stroke_color.hex == "#fff" np.alltrue(m.stroke_rgba == np.array((0.0, 1.0, 0.0, 0.5))) m.set_stroke(BLACK) assert m.stroke_color.hex == "#000" np.alltrue(m.stroke_rgba == np.array((1.0, 1.0, 1.0, 1.0))) m.set_stroke(PURE_GREEN, opacity=0.5) assert m.stroke_color.hex == "#0f0" np.alltrue(m.stroke_rgba == np.array((0.0, 1.0, 0.0, 0.5)))
def test_set_stroke(using_opengl_renderer): m = OpenGLVMobject() m.set_stroke(color=C.ORANGE, width=2, opacity=0.8) assert m.stroke_width == 2 assert m.stroke_opacity == 0.8 assert m.stroke_color == Color(C.ORANGE)
def __init__( self, func: Callable[[np.ndarray], np.ndarray], color: Color | None = None, color_scheme: Callable[[np.ndarray], float] | None = None, min_color_scheme_value: float = 0, max_color_scheme_value: float = 2, colors: Sequence[Color] = DEFAULT_SCALAR_FIELD_COLORS, # Determining stream line starting positions: x_range: Sequence[float] = None, y_range: Sequence[float] = None, z_range: Sequence[float] = None, three_dimensions: bool = False, noise_factor: float | None = None, n_repeats=1, # Determining how lines are drawn dt=0.05, virtual_time=3, max_anchors_per_line=100, padding=3, # Determining stream line appearance: stroke_width=1, opacity=1, **kwargs, ): self.x_range = x_range or [ floor(-config["frame_width"] / 2), ceil(config["frame_width"] / 2), ] self.y_range = y_range or [ floor(-config["frame_height"] / 2), ceil(config["frame_height"] / 2), ] self.ranges = [self.x_range, self.y_range] if three_dimensions or z_range: self.z_range = z_range or self.y_range.copy() self.ranges += [self.z_range] else: self.ranges += [[0, 0]] for i in range(len(self.ranges)): if len(self.ranges[i]) == 2: self.ranges[i] += [0.5] self.ranges[i][1] += self.ranges[i][2] self.x_range, self.y_range, self.z_range = self.ranges super().__init__( func, color, color_scheme, min_color_scheme_value, max_color_scheme_value, colors, **kwargs, ) self.noise_factor = (noise_factor if noise_factor is not None else self.y_range[2] / 2) self.n_repeats = n_repeats self.virtual_time = virtual_time self.max_anchors_per_line = max_anchors_per_line self.padding = padding self.stroke_width = stroke_width half_noise = self.noise_factor / 2 np.random.seed(0) start_points = np.array( [(x - half_noise) * RIGHT + (y - half_noise) * UP + (z - half_noise) * OUT + self.noise_factor * np.random.random(3) for n in range(self.n_repeats) for x in np.arange(*self.x_range) for y in np.arange(*self.y_range) for z in np.arange(*self.z_range)], ) def outside_box(p): return (p[0] < self.x_range[0] - self.padding or p[0] > self.x_range[1] + self.padding - self.x_range[2] or p[1] < self.y_range[0] - self.padding or p[1] > self.y_range[1] + self.padding - self.y_range[2] or p[2] < self.z_range[0] - self.padding or p[2] > self.z_range[1] + self.padding - self.z_range[2]) max_steps = ceil(virtual_time / dt) + 1 if not self.single_color: self.background_img = self.get_colored_background_image() if config["renderer"] == "opengl": self.values_to_rgbas = self.get_vectorized_rgba_gradient_function( min_color_scheme_value, max_color_scheme_value, colors, ) for point in start_points: points = [point] for _ in range(max_steps): last_point = points[-1] new_point = last_point + dt * func(last_point) if outside_box(new_point): break points.append(new_point) step = max_steps if not step: continue if config["renderer"] == "opengl": line = OpenGLVMobject() else: line = VMobject() line.duration = step * dt step = max(1, int(len(points) / self.max_anchors_per_line)) line.set_points_smoothly(points[::step]) if self.single_color: line.set_stroke(self.color) else: if config["renderer"] == "opengl": # scaled for compatibility with cairo line.set_stroke(width=self.stroke_width / 4.0) norms = np.array([ np.linalg.norm(self.func(point)) for point in line.points ], ) line.set_rgba_array_direct( self.values_to_rgbas(norms, opacity), name="stroke_rgba", ) else: if np.any(self.z_range != np.array([0, 0.5, 0.5])): line.set_stroke( [self.pos_to_color(p) for p in line.get_anchors()], ) else: line.color_using_background_image(self.background_img) line.set_stroke(width=self.stroke_width, opacity=opacity) self.add(line) self.stream_lines = [*self.submobjects]