Skip to content

Commit 07fa1fc

Browse files
committed
Refactor Mandelbrot group positioning and enhance bifurcation diagram setup
1 parent a80c6f1 commit 07fa1fc

2 files changed

Lines changed: 165 additions & 19 deletions

File tree

presentation/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ def mandelbrot_to_manim(px, py):
789789
# self.play(FadeIn(bif_points, lag_ratio=0.01), run_time=2)
790790
# self.wait(0.5)
791791

792-
mandelbrot_group.next_to(title, DOWN)
792+
mandelbrot_group.next_to(title, DOWN).set_x(0)
793793

794794
# Mandelbrot (invertido)
795795
self.play(FadeIn(mandelbrot_group, lag_ratio=0.01), run_time=2)

presentation/video.py

Lines changed: 164 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,33 +139,179 @@ def construct(self):
139139

140140
class Testing(ThreeDSlide):
141141
def construct(self):
142-
axes = Axes(
143-
x_range=[0.7, 4, 0.2],
144-
y_range=[0, 1, 0.2],
145-
axis_config={"color": BLUE},
146-
)
147142

148-
labels = axes.get_axis_labels(x_label="r", y_label="x")
149143

150-
self.play(Create(axes), Write(labels))
144+
title = Tex(r"1. Objetivos").to_edge(UP + LEFT)
145+
146+
147+
axes_top = Axes(
148+
x_range=[0, 4, 1],
149+
y_range=[0, 1, 0.2],
150+
x_length=5,
151+
y_length=2.5,
152+
axis_config={"color": BLUE}
153+
)
154+
# Etiquetas
155+
labels_top = axes_top.get_axis_labels(x_label="r", y_label="x")
156+
157+
# Colocamos este grupo arriba en la pantalla
158+
bif_axes_group = VGroup(axes_top, labels_top).to_edge(UP, buff=1.5)
151159

160+
# 2.2) Función logística
152161
def logistic_map(r, x):
153162
return r * x * (1 - x)
154163

155-
def bifurcation_diagram(r_values, iterations, last):
156-
x = np.random.rand(len(r_values))
164+
# 2.3) Generador de puntos para el diagrama
165+
def bifurcation_diagram(r_values, iterations=1000, last=100):
166+
"""
167+
Devuelve (r, x) tras descartar transitorios.
168+
r_values: array de valores de 'r'
169+
iterations: número total de iteraciones
170+
last: cuántas iteraciones finales graficar
171+
"""
172+
x = np.random.rand(len(r_values)) # condiciones iniciales aleatorias
157173
for i in range(iterations):
158174
x = logistic_map(r_values, x)
159-
if i >= (iterations - last):
160-
yield r_values, x
175+
# Sólo generamos puntos en las últimas 'last' iteraciones
176+
if i >= (iterations - last):
177+
yield r_values, x
178+
179+
# 2.4) Creamos los puntos del diagrama
180+
r_values = np.linspace(0, 4.0, 1000)
181+
bif_points = VGroup()
182+
""" for r, x in bifurcation_diagram(r_values, iterations=1000, last=100):
183+
for i in range(len(r)):
184+
dot = Dot(
185+
axes_top.coords_to_point(r[i], x[i]),
186+
radius=0.008,
187+
color=WHITE
188+
)
189+
#bif_points.add(dot)
190+
191+
"""
192+
# ------------------------------------------------
193+
# 3) Conjunto de Mandelbrot (abajo e invertido)
194+
# ------------------------------------------------
195+
# 3.1) Parámetros para el Mandelbrot
196+
RES = 50 # resolución
197+
MAX_ITER = 50 # iteraciones máximas
198+
XMIN, XMAX = -2, 1
199+
YMIN, YMAX = -1.5, 1.5
200+
201+
# Para dibujar "abajo", crearemos un VGroup y luego lo moveremos
202+
mandelbrot_group = VGroup()
203+
204+
# 3.2) Generamos el fractal píxel a píxel
205+
# Definimos un ancho y alto en coordenadas Manim
206+
# (para luego ubicarlo centrado bajo el diagrama).
207+
fractal_width = 7
208+
fractal_height = 7
209+
210+
# Función para mapear (x, y) real a coordenadas de Manim
211+
# centradas, con el mismo ancho que "fractal_width" y alto "fractal_height".
212+
def mandelbrot_to_manim(px, py):
213+
"""
214+
px, py están en [XMIN, XMAX], [YMIN, YMAX].
215+
Devolvemos (X, Y) en la escena, centrados en (0,0) por debajo.
216+
"""
217+
# Proporciones
218+
# 1) normalizamos px a [0,1] respecto a [XMIN, XMAX]
219+
nx = (px - XMIN) / (XMAX - XMIN)
220+
ny = (py - YMIN) / (YMAX - YMIN)
221+
# 2) escalamos al tamaño en la escena
222+
X = fractal_width * (nx - 0.5) # -0.5 para centrar en 0
223+
Y = fractal_height * (ny - 0.5) # -0.5 para centrar en 0
224+
return np.array([X, Y, 0])
225+
226+
for i in range(RES):
227+
for j in range(RES):
228+
# Convertir (i, j) en coordenadas complejas c = x + i y
229+
x = XMIN + (XMAX - XMIN) * i / (RES - 1)
230+
y = YMIN + (YMAX - YMIN) * j / (RES - 1)
231+
c = complex(x, y)
232+
233+
# Iteramos z_{n+1} = z_n^2 + c
234+
z = 0
235+
iteration = 0
236+
while abs(z) <= 2 and iteration < MAX_ITER:
237+
z = z*z + c
238+
iteration += 1
239+
240+
# Color según número de iteraciones (negro->blanco simple)
241+
color = interpolate_color(BLACK, WHITE, iteration / MAX_ITER)
242+
243+
# Representamos cada píxel con un cuadrado
244+
pixel = Square(
245+
side_length=(fractal_width / RES),
246+
fill_opacity=1,
247+
stroke_width=0
248+
)
249+
pixel.set_fill(color)
250+
# Posicionarlo en la escena
251+
pixel.move_to(mandelbrot_to_manim(x, y))
252+
mandelbrot_group.add(pixel)
253+
254+
# Invertimos verticalmente el mandelbrot
255+
# (flip en el eje UP equivaldría a "reflejar" sobre el eje horizontal)
256+
mandelbrot_group.flip(UP)
257+
258+
# Ahora lo desplazamos debajo del diagrama de bifurcación
259+
#mandelbrot_group.next_to(bif_axes_group, DOWN, buff=1.0)
260+
261+
# ------------------------------------------------
262+
# 4) Añadir líneas que conecten r (arriba) con c (abajo)
263+
# ------------------------------------------------
264+
# Supongamos un mapeo lineal: c(r) = -2 + 3r/4
265+
# => si r=0 -> c=-2, si r=4 -> c=1
266+
# Dibujamos líneas en r_line_values = [0,1,2,3,4], por ejemplo
267+
r_line_values = [1, 3, 3.45, 3.85]
268+
lines_group = VGroup()
269+
270+
for rv in r_line_values:
271+
# Coordenada X en el diagrama de bifurcación (arriba)
272+
top_x = axes_top.coords_to_point(rv, 1.0) # y=1 (para que baje desde "arriba")
273+
# Calculamos c
274+
c_val = -2 + 3*rv/4.0
275+
# Lo llevamos al mandelbrot "invertido"
276+
# Tomamos y=0 (eje real) antes de la inversión
277+
# => (c_val, 0) en el plano del fractal
278+
# Convertimos a la posición en la escena con la misma función,
279+
# y luego aplicamos la inversión que ya hicimos con .flip(UP).
280+
# Para no complicarnos, simplemente localizamos el pixel en y=0:
281+
bottom_point_before_flip = mandelbrot_to_manim(c_val, 0)
282+
# Como ya hemos hecho un flip vertical, la posición en la escena
283+
# es la misma. Solo necesitamos el SHIFT que le dimos a mandelbrot_group.
284+
# Extraemos la posición final sumando su center:
285+
bottom_x = bottom_point_before_flip + mandelbrot_group.get_center() - ORIGIN
286+
287+
# Creamos la línea
288+
line = DashedLine(
289+
start=top_x,
290+
end=bottom_x,
291+
dash_length=0.05,
292+
color=YELLOW
293+
)
294+
lines_group.add(line)
161295

162-
r_values = np.linspace(0.7, 4.0, 15000)
163-
points = VGroup()
296+
# ------------------------------------------------
297+
# 5) Añadimos todo a la escena
298+
# ------------------------------------------------
299+
self.play(FadeIn(title))
300+
self.wait(0.5)
164301

165-
for r, x in bifurcation_diagram(r_values, 1000, 100):
166-
for i in range(len(r)):
167-
points.add(Dot(axes.coords_to_point(r[i], x[i]), radius=0.01, color=WHITE))
302+
# Diagrama de bifurcación
303+
# self.play(FadeIn(bif_axes_group))
304+
# self.play(FadeIn(bif_points, lag_ratio=0.01), run_time=2)
305+
# self.wait(0.5)
168306

169-
self.play(FadeIn(points, lag_ratio=0.01), run_time=2)
170-
self.wait()
307+
mandelbrot_group.next_to(title, DOWN).set_x(0)
308+
309+
# Mandelbrot (invertido)
310+
self.play(FadeIn(mandelbrot_group, lag_ratio=0.01), run_time=2)
311+
self.wait(0.5)
312+
313+
# Líneas de conexión
314+
# self.play(Create(lines_group))
315+
# self.wait(2)
316+
171317

0 commit comments

Comments
 (0)