l conjunto de Mandelbrot, investigado por Beniot Mandelbrot cuando estudia la transición hacia el caos en los sistemas clásicos, es uno de los más conocidos ejemplos de fractales (estructura que se autoreplica en todas las escalas)

Se trata de una sencilla serie iterativa, aplicada en el plano complejo y que se define de esta forma:

Zn+1 = Zn2 + C

con

Z0 = 0

Se suele representar el resultado de la evolución para los valores de distintos valores de C: para los valores para los que $|Z_n| > 2$ la serie diverge y para los restantes se seuele representar con un color más claro cuánto mas tarda (el n) en empezar a diverger, o en blanco si no diverge.

Al representarlo gráfiamente nos encontramos con una figura muchísimo más compleja de lo que podíamos imaginar:

Conjunto de Mandelbrot

La sorpresa es aún mayor si ampliamos determinadas zonas y nos encontramos ¡pequeñas copia del conjunto de Mandelbrot completo!

pequeña copia del conjunto de Mandelbrot

Con este programa vas a poder navegar seleccionando con el ratón la zona que quieres ampliar.

  • Puslando la tecla «s» se guardan las coordenadas actuales (todavía no se pueden cargar….)
  • Pulsando la tecla «i» se guardar la imagen actual

import pygame
import time

width = 1600//2
height = 1200//2
max_iteracion = 220
factor_color = 220 // max_iteracion

ROJO   = (255,   0,   0)

x0Min = -2.1
y0Min = -1.2
x0Max =  0.8
y0Max =  1.2

stepX = 1
stepY = stepX

def resetView():
    global  x0Min, y0Min, x0Max, y0Max 
    x0Min = -2.1
    y0Min = -1.2
    x0Max =  0.8
    y0Max =  1.2

def calculateFactors():
    global fx0, fy0, x0Min, y0Min, x0Max, y0Max 
    dx0 = x0Max - x0Min
    dy0 = y0Max - y0Min

    fx0 = dx0/width
    fy0 = dy0/height

    
def iteraMandelbrot(x0,y0):
    x, y = 0, 0
    iteracion = 0
    while iteracion < max_iteracion and x*x + y*y < 4 :
        xnew = x*x - y*y + x0
        y = 2*x*y + y0

        x = xnew
        iteracion += 1
       
    return iteracion


def init():
    global screen
    pygame.init()
    creaRangoColor()
    screen = pygame.display.set_mode((width,height))
    pygame.display.set_caption("Mandelbrot Set")

colores = [];
def creaRangoColor():
    for i in range(max_iteracion+1):
        colores.append(((max_iteracion -i)*factor_color, 0, i * factor_color))

def drawMandelbrot(i0=0,j0=0,stepI=1,stepJ=1,clear = False):
    global screen,fx0,fy0,x0Min,y0Min
    if clear:
        screen.fill((0,0,0))

    for i in range(i0,width,stepI):
        for j in range(j0,height,stepJ):
            x0 = i*fx0 + x0Min
            y0 = j*fy0 + y0Min

            iteracion = iteraMandelbrot(x0,y0)
           
            color = iteracion * factor_color
            screen.set_at((i,j), (color,color,color))
            #screen.set_at((i,j), colores[iteracion])
            

        pygame.display.flip()
        

def repintaZona():
    global fractal
    calculateFactors()
    screen.fill((0,0,0))
    drawMandelbrot()
    fractal = screen.copy() 

def refrescaPantalla():
    screen.blit(fractal, (0,0))
    pygame.display.flip()

def main():

    init()
    repintaZona()

    running = True
    bDrawRect = False
    rectangle_draging = False
    rectangle = pygame.Rect(0,0,0,0)
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    running = False
                elif event.key == pygame.K_s:  # guardamos las coordenadas actuales
                    fichero = 'coordenas'+time.strftime('%Y%m%d-%H%M%S')+'.txt'
                    f = open(fichero,'wt')
                    str = f'x0Min:{x0Min}\n' + f'y0Min:{y0Min}\n' + \
                        f'x0Max:{x0Max}\n' + f'y0Max:{y0Max}\n'
                    f.write(str)
                    f.close()
                    print(f'Datos guardados en {fichero}')
                elif event.key == pygame.K_i:  # guardamos la imagen a fichero
                    fichero = 'imagen'+time.strftime('%Y%m%d-%H%M%S')+'.png'
                    pygame.image.save(screen,fichero)
                    print(f'Salvada imagen a {fichero}')
                elif event.key == pygame.K_r:  # volvemos al zoom original
                    resetView()
                    repintaZona()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    if rectangle_draging == False:
                        rectangle.x,rectangle.y = event.pos
                        rectangle_draging = True
            elif event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:            
                    rectangle_draging = False
                    # calculamos el rectangulos en coordenadas de pantlla
                    x1,y1 = event.pos
                    rectangle.width   = x1 - rectangle.x
                    rectangle.height  = y1 - rectangle.y
                    # guardamos los valores antiguos
                    x0MinOld, y0MinOld = x0Min,y0Min
                    # calculamos la nuevas coordenadas a dibujar
                    x0Min = rectangle.x * fx0 + x0MinOld
                    y0Min = rectangle.y * fy0 + y0MinOld
                    x0Max = (rectangle.x + rectangle.width)  * fx0 + x0MinOld
                    y0Max = (rectangle.y + rectangle.height) * fy0 + y0MinOld
                    # repintamos
                    repintaZona()
                    refrescaPantalla()
                    bDrawRect = False

            elif event.type == pygame.MOUSEMOTION:
                if rectangle_draging:
                    bDrawRect = True
                    x1,y1 = event.pos
                    rectangle.width   = x1 - rectangle.x
                    rectangle.height  = y1 - rectangle.y
                    
        if bDrawRect:
            screen.blit(fractal, (0,0))
            pygame.draw.rect(screen, ROJO, rectangle,width = 1) 
            pygame.display.flip()
            
    pygame.quit()

if __name__ == '__main__':
    main()
Dibujando el conjunto de Mandelbrot con Python