Fraktale in Python. Exemplarische Vorgehensweise

Hallo Habr! Der heutige Beitrag zu Fraktalen ist Teil eines Python- Themas , insbesondere Matplotlib. Folgen Sie dem Beispiel des Autors und warnen Sie, dass es in dem Beitrag viele umfangreiche Animationen gibt, die möglicherweise nicht einmal auf einem mobilen Gerät funktionieren. Aber wie schön.



Alle lesen gerne

Fraktale sind wunderschön. Sie richten sich nach einem sehr komplexen Muster aus und bleiben bei jeder Vergrößerung verzerrungsfrei erhalten! In diesem Artikel werden wir uns ansehen, wie Sie leicht Fraktale verschiedener Art zeichnen können, indem Sie ein Tool namens L-Systems und das Turtle-Modul für Python verwenden, um Schritt für Schritt zu zeichnen.

In diesem Artikel werden wir nicht übermäßig auf technische Details eingehen. Stattdessen beschränke ich mich auf eine kurze Einführung, zeige viele animierte Beispiele und Code, mit denen Sie ein solches Beispiel generieren können. Wenn Sie die Theorie überspringen und nur die Animation ansehen möchten, gehen Sie direkt zu den Beispielen. Darüber hinaus werde ich am Ende auf einige Ressourcen hinweisen, sowohl beim Schreiben von Code als auch in der grundlegenden Mathematik, die Sie möglicherweise untersuchen möchten.

Was ist ein Fraktal?

Lassen Sie uns zunächst eine „lose“ Definition eines Fraktals geben. Im Prinzip ist ein Fraktal eine geometrische Figur, die unabhängig vom Grad der Zunahme dieselben Eigenschaften aufweist.

Diese Definition ist nicht perfekt, daher hier eine genauere von der Math World-Website:
Ein Fraktal ist ein Objekt oder eine Größe, die auf jeder Skala Selbstähnlichkeit (im formalen Sinne) zeigt. Ein Objekt weist keine identischen Strukturen in verschiedenen Maßstäben auf, aber Strukturen desselben „Typs“ müssen auf allen Ebenen des Fraktals auftreten. In diesem Fall wird der Graph in einem Koordinatensystem mit einer logarithmischen Skala dargestellt, wobei die Größe und der Maßstab entlang der Achsen gezählt werden. Der Graph ist eine gerade Linie mit einer Steigung, die die Dimension des Fraktals widerspiegelt. - Mathe-Welt

Wie zeichne ich Fraktale mit Python?

Typischerweise ist das Rendern von Fraktalen komplex, da die Tiefe von Fraktalen durch das Konzept der Rekursion bestimmt wird. Wenn wir über Graphen und ihre Zeichnung sprechen, denken wir normalerweise, dass sie durch Pixel oder Vektoren gebildet werden, aber die Anzahl der Pixel oder Vektoren ist immer begrenzt und Fraktale sind per Definition unendlich rekursiv. Wenn wir also versuchen, ein Fraktal auf das Koordinatengitter anzuwenden, müssen wir irgendwann aufhören, und deshalb sprechen wir in diesem Fall von „Iterationen“. Bei jeder Iteration wird das Fraktal komplizierter, und irgendwann wird es unmöglich, zwei seiner Iterationen nacheinander zu unterscheiden (ein solcher Moment tritt auf, wenn Änderungen auf einer Ebene auftreten, die mit der Größe des Pixels vergleichbar ist). Es ist logisch, hier anzuhalten, aber in der Regel zeichnet sich die Form des Fraktals schneller ab, und Sie können noch früher anhalten.

Zwei solche Beispiele sind die quadratische Insel Koch, deren Struktur nach drei Iterationen deutlich sichtbar wird, und der Carter-Heitway-Drache, für den 8 Iterationen ausreichen, um die vollständige Struktur aufzubauen. Die erforderliche Anzahl von Iterationen hängt stark von dem spezifischen Fraktal ab, mit dem wir arbeiten.

Natürlich gibt es viele Python-Bibliotheken zum Plotten, von denen die beliebteste Matplotlib ist, aber sie sind normalerweise zum Zeichnen von Statistiken und zum Zeichnen bekannter Diagramme konzipiert. Insbesondere enthält Matplotlib einige Konstruktionen auf niedriger Ebene, mit denen Fraktale konstruiert werden können. Dieses Mal konzentrieren wir uns jedoch auf das unverdient wenig bekannte Modul der Standardbibliothek namens Turtle.

Turtle-Modul

in der Python-DokumentationWir lesen: „Turtle Graphics ist ein beliebtes Werkzeug für die erste Bekanntschaft von Kindern mit Programmierung. Er war Teil der ursprünglichen Programmiersprache Logo, die 1966 von Wally Förzeg und Seymour Papert entwickelt wurde. “

Unter dem Strich erkennt die Schildkröte standardmäßig 3 Befehle:

  • Vorwärts kriechen
  • Linken Winkel drehen
  • Im rechten Winkel drehen

Hinweis: Andere Befehle sind in der Standardbibliothek enthalten, hier werden jedoch nur diese drei verwendet.

Auch können wir:

  • Aufnahme stumm schalten
  • Aufnahme aktivieren

Diese Eigenschaften scheinen zu einfach zu sein, um auf ein so komplexes Diagramm wie ein Fraktal zurückzugreifen, das sich nur auf sie stützt. Wir werden jedoch ein anderes Werkzeug verwenden, das nur diesen kleinen Satz von Anweisungen verwendet. Ich spreche von L-Systemen.

L-Systeme Ein

L-System ist eine Möglichkeit, rekursive Strukturen (z. B. Fraktale) als Zeichenfolge darzustellen und eine solche Zeichenfolge mehrmals umzuschreiben. Wieder geben wir eine formale Definition:
Das Lindenmeyer-System, auch als L-System bekannt, ist ein Mechanismus zum Umschreiben von Linien, mit dem Fraktale mit Dimensionen von 1 bis 2 erzeugt werden können - Math World

Nachdem wir verstanden haben, was ein L-System ist, können wir rekursive Strukturen erstellen, aber zuerst wollen wir herausfinden, welche Komponenten wir dafür benötigen. Jedes L-System hat:

  • : , L-.
  • : .
  • : , .

Hinweis für Informatikfans: Wenn Sie Informatik eingehend studiert haben, erinnern Sie all das möglicherweise an etwas. In der Tat sind formale Grammatiken sehr ähnlich definiert; Der Hauptunterschied besteht darin, dass im Gegensatz zu Grammatiken hier bei jeder Iteration so viele Regeln wie möglich gelten und nicht nur eine. Daher sind L-Systeme eine Teilmenge kontextfreier Grammatiken.

Da wir Turtle verwenden werden, um Diagramme zu erstellen, und das L-System, um darzustellen, was wir zeichnen werden, müssen wir eine Beziehung zwischen ihnen herstellen.

Da wir in Turtle nur die oben aufgeführten Teams haben, weisen wir jedem von ihnen ein Symbol zu. Das Alphabet besteht aus diesen Zeichen.

  • F: vorwärts kriechen
  • +: rechts abbiegen
  • -: Biegen Sie links ab

Damit dies funktioniert, muss für jedes Fraktal ein Winkel angegeben werden. Dies ist der Winkel, in dem sich die Schildkröte nach rechts oder links dreht. Der Einfachheit halber sind wir uns einig, dass nur eine Ecke vorgesehen werden sollte, und wir werden das L-System schreiben, wobei wir dies berücksichtigen.
Das Axiom und die Anweisungen zum Erstellen von Zeichenfolgen hängen nur vom Fraktal ab. Das Fraktal muss jedoch so geschrieben werden, dass es nur durch diese drei Zeichen dargestellt werden kann. Es gibt also eine Einschränkung, aufgrund derer wir nur einzeilige Fraktale erstellen können, dh so etwas wie die Cantor-Menge kann auf diese Weise nicht erhalten werden. Dies ist jedoch nur eine Vereinfachung, da wir immer zwei andere Befehle eingeben können, um vorwärts zu gehen, ohne aufzuzeichnen, und denselben, um rückwärts zu gehen.

Kommen wir nun zu den Beispielen!

Animierte Beispiele

Die folgenden Beispiele wurden online aus mehreren öffentlich verfügbaren Quellen entnommen, und ich habe beschlossen, sie mithilfe des Turtle-Moduls nach Python zu portieren, zu zentrieren, zu kolorieren und eine Möglichkeit zum Exportieren in ein Vektorformat bereitzustellen.

ACHTUNG: Die vorgeschlagenen Animationen sind ziemlich groß. Es wird empfohlen, sie nur mit gutem Internet anzusehen. Der Repl-Code funktioniert möglicherweise nicht, da er Ihre Ressourcen verbraucht und Probleme beim Anzeigen von Fraktalen auf Mobilgeräten auftreten können.

Hinweis: Skulpt verwendet IHREN BROWSER zum Rendern und Erstellen von Animationen. Wenn Sie also hängen bleiben, sich verzögern oder ein seltsames Verhalten zeigen, reicht es normalerweise aus, die Animation erneut abzuspielen oder die Seite neu zu laden. Funktioniert möglicherweise nicht auf Mobilgeräten.

Die Beispiele sind in der Reihenfolge ihrer Komplexität angegeben (meiner subjektiven Meinung nach), das Interessanteste ist also am Ende.

Koch Schneeflocke

axiom = "F--F--F"
rules = {"F":"F+F--F+F"}
iterations = 4 # TOP: 7
angle = 60


Koch Square Island

axiom = "F+F+F+F"
rules = {"F":"F-F+F+FFF-F-F+F"}
iterations = 2 # TOP: 4
angle = 90


Kristall

axiom = "F+F+F+F"
rules = {"F":"FF+F++F+F"}
iterations = 3 # TOP: 6
angle = 90


Quadratische Schneeflocke

axiom = "F--F"
rules = {"F":"F-F+F+F-F"}
iterations = 4 # TOP: 6
angle = 90


Fraktale Wicheka

axiom = "F-F-F-F"
rules = {"F":"F-F+F+F-F"}
iterations = 4 # TOP: 6
angle = 90


Abgabekurve

axiom = "F"
rules = {"F":"+F--F+"}
iterations = 10 # TOP: 16
angle = 45


Sierpinski Teppich

axiom = "YF"
rules = {"X":"YF+XF+Y", "Y":"XF-YF-X"}
iterations = 1 # TOP: 10
angle = 60


Sierpinski-Gitter

axiom = "FXF--FF--FF"
rules = {"F":"FF", "X":"--FXF++FXF++FXF--"}
iterations = 7 # TOP: 8
angle = 60


Quadrat

axiom = "F+F+F+F"
rules = {"F":"FF+F+F+F+FF"}
iterations = 3 # TOP: 5
angle = 90


Fliesen

axiom = "F+F+F+F"
rules = {"F":"FF+F-F+F+FF"}
iterations = 3 # TOP: 4
angle = 90


Ringe

axiom = "F+F+F+F"
rules = {"F":"FF+F+F+F+F+F-F"}
iterations = 2 # TOP: 4
angle = 90


Kreuz 2

axiom = "F+F+F+F"
rules = {"F":"F+F-F+F+F"}
iterations = 3 # TOP: 6
angle = 90


Pentaplexität

axiom = "F++F++F++F++F"
rules = {"F":"F++F++F+++++F-F++F"}
iterations = 1 # TOP: 5
angle = 36


32 Segmentkurve

axiom = "F+F+F+F"
rules = {"F":"-F+F-F-F+F+FF-F+F+FF+F-F-FF+FF-FF+F+F-FF-F-F+FF-F-F+F+F-F+"}
iterations = 3 # TOP: 3
angle = 90


Peano Gosper Kurve

axiom = "FX"
rules = {"X":"X+YF++YF-FX--FXFX-YF+", "Y":"-FX+YFYF++YF+FX--FX-Y"}
iterations = 4 # TOP: 6
angle = 60


Sierpinski-Kurve

axiom = "F+XF+F+XF"
rules = {"X":"XF-F+F-XF+F+XF-F+F-X"}
iterations = 4 # TOP: 8
angle = 90


Krishnas Fragebögen

axiom = " -X--X"
rules = {"X":"XFX--XFX"}
iterations = 3 # TOP: 9
angle = 45


Gosper Square Fractal

axiom = "YF"
rules = {"X": "XFX-YF-YF+FX+FX-YF-YFFX+YF+FXFXYF-FX+YF+FXFX+YF-FXYF-YF-FX+FX+YFYF-", 
        "Y": "+FXFX-YF-YF+FX+FXYF+FX-YFYF-FX-YF+FXYFYF-FX-YFFX+FX+YF-YF-FX+FX+YFY"}
iterations = 2 # TOP: 3
angle = 90


Moore-Kurve

axiom = "LFL-F-LFL"
rules = {"L":"+RF-LFL-FR+", "R":"-LF+RFR+FL-"}
iterations = 0 # TOP: 8
angle = 90


Hilbert-Kurve

axiom = "L"
rules = {"L":"+RF-LFL-FR+", "R":"-LF+RFR+FL-"}
iterations = 8 # TOP: 9
angle = 90


Hilbert-Kurve II

axiom = "X"
rules = {"X":"XFYFX+F+YFXFY-F-XFYFX", "Y":"YFXFY-F-XFYFX+F+YFXFY"}
iterations = 4 # TOP: 6
angle = 90


Peano-Kurve

axiom = "F"
rules = {"F":"F+F-F-F-F+F+F+F-F"}
iterations = 2 # TOP: 5
angle = 90


Kreuz

axiom = "F+F+F+F"
rules = {"F":"F+FF++F+F"}
iterations = 3 # TOP: 6
angle = 90


Dreieck

axiom = "F+F+F"
rules = {"F":"F-F+F"}
iterations = 2 # TOP: 9
angle = 120


Drachenkurve

axiom = "FX"
rules = {"X":"X+YF+", "Y":"-FX-Y"}
iterations = 8 # TOP: 16
angle = 90


Terdragon-Kurve

axiom = "F"
rules = {"F":"F-F+F"}
iterations = 5 # TOP: 10
angle = 120


Doppelte Drachenkurve

axiom = "FX+FX"
rules = {"X":"X+YF+", "Y":"-FX-Y"}
iterations = 6 # TOP: 16
angle = 90


Dreifache Drachenkurve

axiom = "FX+FX+FX"
rules = {"X":"X+YF+", "Y":"-FX-Y"}
iterations = 7 # TOP: 15
angle = 90


Code

Alle oben genannten Beispiele wurden mit demselben Code erhalten, und bei der Bearbeitung traten einige Schwierigkeiten auf (z. B. wie das Fraktal so weit wie möglich in der Mitte gehalten werden kann), indem mit Farbe, Inversion, Offsets gearbeitet und ein schneller Export nach bereitgestellt wurde Vektorformat. Hier zeige ich Ihnen nur die einfachste Version.
Diese Version zeigt Fraktale in Schwarzweiß an und ist nicht mit Exportfunktionen ausgestattet

import turtle

def create_l_system(iters, axiom, rules):
    start_string = axiom
    if iters == 0:
        return axiom
    end_string = ""
    for _ in range(iters):
        end_string = "".join(rules[i] if i in rules else i for i in start_string)
        start_string = end_string

    return end_string


def draw_l_system(t, instructions, angle, distance):
    for cmd in instructions:
        if cmd == 'F':
            t.forward(distance)
        elif cmd == '+':
            t.right(angle)
        elif cmd == '-':
            t.left(angle)


def main(iterations, axiom, rules, angle, length=8, size=2, y_offset=0,
        x_offset=0, offset_angle=0, width=450, height=450):

    inst = create_l_system(iterations, axiom, rules)

    t = turtle.Turtle()
    wn = turtle.Screen()
    wn.setup(width, height)

    t.up()
    t.backward(-x_offset)
    t.left(90)
    t.backward(-y_offset)
    t.left(offset_angle)
    t.down()
    t.speed(0)
    t.pensize(size)
    draw_l_system(t, inst, angle, length)
    t.hideturtle()

    wn.exitonclick()


Code Erklärung

import turtle


Zuerst müssen Sie das Turtle-Modul importieren

def create_l_system(iters, axiom, rules):
    start_string = axiom
    if iters == 0:
        return axiom
    end_string = ""
    for _ in range(iters):
        end_string = "".join(rules[i] if i in rules else i for i in start_string)
        start_string = end_string

    return end_string

Dann müssen Sie ein L-System generieren, das eine Reihe von Anweisungen für die Schildkröte enthält. Wir definieren eine Funktion create_l_system, die die Anzahl der Iterationen, ein Axiom und Konstruktionsregeln erhält. Es beginnt mit einem Axiom und verwendet eine Hilfsvariable end_string. Wenn die Iteration 0 ist, gibt es das Axiom zurück, da einige Fraktale auch mit Iterationen von Null angewendet werden können. In diesem Fall wird davon ausgegangen, dass die Regeln die Form von Wörterbüchern haben, sodass jeder Schlüssel eindeutig ist, ein Symbol darstellt und der Wert angibt, was und was ersetzt werden muss. Also kombinieren wir alle Ersetzungen für jedes Zeichen und erhalten schließlich eine Zeichenfolge für die nächste Iteration.

def draw_l_system(t, instructions, angle, distance):
    for cmd in instructions:
        if cmd == 'F':
            t.forward(distance)
        elif cmd == '+':
            t.right(angle)
        elif cmd == '-':
            t.left(angle)

Dann bestimmen wir, draw_l_systemwelche die Schildkröte akzeptiert, eine Reihe von Anweisungen (Ausgabe des L-Systems), den Winkel zum Drehen nach links oder rechts und die Länge jeder einzelnen Linie. Es besteht aus einer einfachen Struktur eliffür jedes der zuvor definierten Teams.

def main(iterations, axiom, rules, angle, length=8, size=2, y_offset=0,
        x_offset=0, offset_angle=0, width=450, height=450):

    inst = create_l_system(iterations, axiom, rules)

    t = turtle.Turtle()
    wn = turtle.Screen()
    wn.setup(width, height)

    t.up()
    t.backward(-x_offset)
    t.left(90)
    t.backward(-y_offset)
    t.left(offset_angle)
    t.down()
    t.speed(0)
    t.pensize(size)
    draw_l_system(t, inst, angle, length)
    t.hideturtle()

    wn.exitonclick()

Schließlich lassen Sie uns sprechen über die Funktion main, die alle notwendigen Parameter für die Erzeugung von L-Systemen nimmt, sowie y_offset, x_offset, offset_angle, widthund height. Die ersten drei beschreiben die Verschiebung der Schildkröte. Es ist lediglich erforderlich, das Diagramm so auf der Leinwand zu positionieren, wie wir es möchten.

Die Funktion generiert zuerst eine Reihe von Anweisungen und speichert sie in inst. Dann initialisiert sie die Schildkröte und den Bildschirm und platziert die Schildkröte an einem bestimmten Punkt. Anschließend zeichnet sie eine Grafik gemäß den Anweisungen und wartet, bis ein Klick geschlossen wird.

Besondere Überlegungen

Wie oben erwähnt, bleiben hier viele Einschränkungen. Erstens haben wir der Schildkröte nicht die Möglichkeit gegeben, sich ohne Rendern zu bewegen. Dies würde ein anderes Zeichen erfordern. Es gibt auch kein Symbol, um sich zurückzuziehen und sich an frühere Positionen zu erinnern. Sie waren nicht für alle oben diskutierten Fraktale erforderlich, aber für einige andere (z. B. Fraktalbäume).

Zusätzliche Ressourcen

Das Internet verfügt über viele Ressourcen zu Fraktalen, die sowohl aus programmtechnischer als auch aus mathematischer Sicht betrachtet werden. Die folgenden beiden schienen mir besonders interessant zu sein: 3Blue1Brown (Mathematik) und CodingTrain (Code).

Der Artikel wurde von einem Beitrag von Math World und dem Artikel inspiriert Paula Burka.

All Articles