Intro | Installation | Usage | L-System Instructions | Examples | Links
TurtLSystems is a Python 3 package for drawing L-systems via turtle graphics with easy ways to output png images and gif animations of the patterns generated. L-systems or Lindenmayer systems are a simple string rewriting systems where every character in an initial start string is repeatedly overwritten with a predetermined replacement. This can lead to very elaborate patterns that create fractals or mimic nature.
Do pip install TurtLSystems
then run the following Python to draw a Sierpinski triangle:
from TurtLSystems import *
draw()
wait()
Make sure you have Python installed then run this command in a terminal:
pip install TurtLSystems
If that doesn't work try one of the following lines:
pip3 install TurtLSystems
python -m pip install TurtLSystems
python3 -m pip install TurtLSystems
py -m pip install TurtLSystems
For png and gif output the Ghostscript conversion tool is required. It can be downloaded here. Ghostscript is what takes the .eps files generated by turtle graphics and turns them into pngs which are then made into gifs.
The Python imaging library Pillow (PIL) is also required for png and gif output but it will be installed automatically when you install TurtLSystems.
TurtLSystems on PyPI | TurtLSystems on GitHub | Ghostscript Download
TurtLSystems has only four functions, init
, draw
, wait
, and lsystem
,
and only the draw
function is strictly necessary.
The code that generated the blue gif of the Sierpinski arrowhead curve above is simply:
from TurtLSystems import *
draw('A', 'A B-A-B B A+B+A,', 5, 60, 7, 2, (200, 220, 255), None, (36, 8, 107),
heading=60, red_increment=2, gif='example.gif', max_frames=250, duration=30)
A typical program might look like:
from TurtLSystems import init, draw, wait
init(...) # fill in args
draw(...) # fill in args
wait()
To ignore the errors that get thrown when exiting the window while the turtle is drawing use try/except with Exit
:
from TurtLSystems import init, draw, wait, Exit
try:
init(...) # fill in args
draw(...) # fill in args
wait()
except Exit:
pass
Initializes global TurtLSystems properties.
Calling this is optional and only needed when customization is desired.
If used it should only be called once and placed before all calls to draw
and wait
.
Returns nothing.
NameDefault |
DescriptionType |
---|---|
window_size(0.75, 0.75) |
The size of the window. Use integers for pixel dimensions. Use floats for a percentage of the screen size.Tuple[int | float, int | float] |
window_title"TurtLSystems" |
The title of the window.str |
background_color(0, 0, 0) |
The background color of the window. A 0-255 rgb tuple. May be changed later by draw calls.Tuple[int, int, int] |
background_imageNone |
The file path to a background image for the window.str | None |
window_positionNone |
The top and left screen coordinates of the window, or None for centered.Tuple[int | None, int | None] | None |
canvas_sizeNone |
The size of the drawing canvas when an area larger than the window size is desired.Tuple[int | None, int | None] | None |
ghostscriptNone |
The path to or command name of ghostscript. When None, an educated guess of the path is made on Windows and 'gs' is used on Mac/Linux. Ghostscript is the image conversion tool required for png and gif output.str | None |
logo_modeFalse |
Whether the turtle graphics coordinates mode is 'standard' or 'logo'. Defaults to standard. In standard mode an angle of 0 points rightward and positive angles go counterclockwise. In logo mode an angle of 0 points upward and positive angles go clockwise.bool |
delayNone |
The turtle graphics animation delay in milliseconds. None for default value.int | None |
silentFalse |
Whether to silence all messages and warnings produced by TurtLSystems.bool |
If you have issues where png or gif output is cut off and doesn't match what is shown in the window, try increasing
the canvas size to much larger than needed like init(canvas_size(2000, 2000))
.
I experienced this issue in Linux Mint and am not sure why it happened.
Opens a turtle graphics window and draws an L-system pattern based on the arguments provided. When called multiple times all patterns are drawn to the same canvas.
All 54 arguments are optional but start
and rules
are the most important because they define the L-system,
and level
defines how many expansion steps take place. On an expansion step, every character in start
is
replaced with what it maps to in rules
(or left unchanged if not present) resulting in a new start
string.
The characters of start
after the last expansion are the instructions the turtle follows to draw a pattern.
See the lsystem
function documentation for specifics on what each character does as an instruction.
Call draw()
by itself to see an example Sierpinski triangle pattern.
In the descriptions below, "on X" is short for "when the character X is encountered in the L-system string".
Returns a 2-tuple of the final L-system string and the turtle graphics Turtle object used to draw the pattern
(Tuple[str, turtle.Turtle]
).
NameDefault |
DescriptionType |
---|---|
start'F+G+G' |
The initial string or axiom of the L-system. Level 0.str |
rules'F F+G-F-G+F G GG' |
Dictionary that maps characters to what they are replaced with in the L-system expansion step. May also be a string where whitespace separated pairs of substrings correspond to the character and its replacement. For example {'A': 'AB', 'B': 'B+A'} and 'A AB B B+A' represent the same rules.Dict[str, str] | str |
level4 |
The number of L-system expansion steps to take, i.e. how many times to apply rules to start .int |
angle120 |
The angle to turn by on + or - . In degrees by default but the circle arg can change that.float |
length20 |
The distance in pixels to move forward by on letters. The length step.float |
thickness1 |
The line width in pixels. May be any non-negative number.float |
color(255, 255, 255) |
The line color. A 0-255 rgb tuple or None to hide all lines. Reselected on 0 .Tuple[int, int, int] | None |
fill_color(128, 128, 128) |
The fill color for {} polygons, @ dots, and turtle shapes. A 0-255 rgb tuple or None to hide all fills. Reselected on 1 .Tuple[int, int, int] | None |
background_colorNone |
The background color of the window. A 0-255 rgb tuple or None to leave unchanged.Tuple[int, int, int] | None |
asapFalse |
When True the draw will happen as fast as possible, ignoring speed arg and the delay arg of init .bool |
NameDefault |
DescriptionType |
---|---|
colorsNone |
When an iterable such as a list, color and fill_color are ignored and the first 10 colors of the list become the colors that are selected on 0 through 9 . Each may be a 0-255 rgb tuple or None for no color. The list of defaults below is used to fill out anything missing if less than 10 colors are given. When colors is None, color and fill_color are used replace slots 0 and 1 respectively.Iterable[Tuple[int, int, int] | None] | None |
position(0, 0) |
The initial (x, y) position of the turtle.Tuple[float, float] |
heading0 |
The initial angle the turtle points in.float |
scale1' |
A factor to scale the size of the pattern by. May be negative. Specifically, length , position , and length_increment are multiplied by scale and thickness and thickness_increment are multiplied by abs(scale) .float |
prefix'' |
An L-system string that does not undergo expansion prepended to the fully expanded start string.str |
suffix'' |
An L-system string that does not undergo expansion appended to the fully expanded start stringstr |
max_charsNone |
The maximum number of characters in the final L-system string (prefix + expanded start + suffix ) to follow the instructions for, or None for no limit.int | None |
max_drawsNone |
The maximum number of "draw" operations to do or None for no limit. A "draw" operation is something that draws to the canvas, namely lines from uppercase letters, dots from @ , and finished polygons from } .int | None |
Default Colors:
-
0 = (255, 255, 255)
white -
1 = (128, 128, 128)
gray -
2 = (255, 0, 0)
red -
3 = (255, 128, 0)
orange -
4 = (255, 255, 0)
yellow -
5 = (0, 255, 0)
green -
6 = (0, 255, 255)
cyan -
7 = (0, 0, 255)
blue -
8 = (128, 0, 255)
purple -
9 = (255, 0, 255)
magenta
NameDefault |
DescriptionType |
---|---|
speed'fastest' |
The speed of the turtle. An integer from 1 to 10 for slowest to fastest or 0 for the fastest possible. Strings 'slowest', 'slow', 'normal', 'fast', and 'fastest' correspond to 1, 3, 6, 10, and 0 respectively.int | str |
show_turtleFalse |
Whether the turtle is shown or not.bool |
turtle_shape'classic' |
The shape of the turtle. Can be 'classic', 'arrow', 'turtle', 'circle', 'square', or 'triangle'.str |
circle360 |
The number of degrees to consider a full circle as having. Use 2*math.pi to work in radians.float |
NameDefault |
DescriptionType |
---|---|
angle_increment15 |
The amount to increment or decrement angle by on ) or ( .float |
length_increment5 |
The amount to increment or decrement length by on ^ or % .float |
length_scalar2 |
The amount to multiply or divide length by on * or / .float |
thickness_increment1 |
The amount to increment or decrement the thickness by on > or < . Thickness won't go below 0.float |
red_increment1 |
The amount to increment or decrement the red channel of the line or fill color by on , or . . Channel will stay in the range [0, 255]. This can be a float to allow for gradual changes.float |
green_increment1 |
The amount to increment or decrement the green channel of the line or fill color by on ; or : . Channel will stay in the range [0, 255]. This can be a float to allow for gradual changes.float |
blue_increment1 |
The amount to increment or decrement the blue channel of the line or fill color by on ? or ! . Channel will stay in the range [0, 255]. This can be a float to allow for gradual changes.float |
NameDefault |
DescriptionType |
---|---|
textNone |
A string of text to add to the canvas. Patters are drawn on top of it. None for no text.str | None |
text_color(255, 255, 255) |
The color of the text. A 0-255 rgb tuple or None to hide the text.Tuple[int, int, int] | None |
text_position(0, -200) |
The (x, y) position of the text.Tuple[int, int] |
text_align'center' |
The alignment of the text. Either 'left', 'center', or 'right'.str |
font'Arial |
The font name of the text.str |
font_size16 |
The font size of the text. Measured in points if positive or in pixels if negative.int |
font_style'normal' |
The styling to apply to the font of the text. 'normal', 'bold', 'italic', 'underline' and 'overstrike' are all possibilities and can be combined like 'bold italic'.str |
NameDefault |
DescriptionType |
---|---|
pngNone |
The file path of where to save the final drawing as a png image, or None for no png output. A file extension is not required.str | None |
padding10 |
The amount of padding in pixels to frame the drawing with on all sides in png and gif output. Negative values are valid. When None, no padding happens and the entire canvas area is saved. Note that padding very large blank areas can be slow.int | None |
transparentFalse |
When True, the background of png and gif output is transparent rather that the window background color.bool |
antialiasing4 |
An integer 1, 2, or 4 that specifies how jagged pixel edges will be in png and gif output. 1 for the most jagged, 4 for the least jagged. Note that the window canvas does not respect this option.int |
output_scale1 |
A factor to scale png and gif dimensions by. Vector graphics are used so there is no quality loss from scaling up, though padding may take longer.float |
NameDefault |
DescriptionType |
---|---|
gifNone |
The file path of where to save the drawing as a gif animation, or None for no gif output. A file extension is not required.str | None |
frame_every1 |
When an integer, this is the number of "draw" operations to wait for between recording of gif frames. A "draw" operation is something that draws to the canvas, namely lines from uppercase letters, dots from @ , and finished polygons from } . When a collection such as a string, frames are recorded whenever L-system characters in the collections are encountered.int | Collection[str] |
max_frames100 |
The maximum number of frames of the gif or None for no limit. Useful to prevent accidental creation of very long gifs.int | None |
duration20 |
The duration in milliseconds of each gif frame. Should be 20 or above and divisible by 10.int |
pause500 |
The amount of additional time in milliseconds to pause on the last frame of the gif.int |
defer0 |
The amount of additional time in milliseconds to add to the first frame of the gif.int |
loopsNone |
The number of times the gif loops or 0 or None for no limit.int | None |
reverseFalse |
Whether to reverse the frames of the gif.bool |
alternateFalse |
When True, the central gif frames are copied and appended in reverse to the end of the gif, making it cycle forwards and backwards. For example, a sequence 01234 would become 01234321.bool |
growthFalse |
When True, the gif consist of frames made from the final patterns of every expansion of the start string, from level 0 to level inclusive. frame_every and max_frames are ignored in this mode.bool |
NameDefault |
DescriptionType |
---|---|
tmpdirNone |
The path to a directory to put all .eps and .png files in during the generation of png and gif output. Useful if you need the gif frames as pngs. When None these files are put in a temporary place and deleted.str | None |
callbackNone |
When not None, a function that is called for every character in the L-system string the turtle encounters. Two arguments are given, the current character and the Turtle object. If True is returned the turtle stops.Callable[[str, turtle.Turtle], bool | None] | None |
skip_initFalse |
Whether to skip calling init when it hasn't been called already.bool |
Keeps window open. Calling this is optional.
If used it should only be called once and be placed after all calls to draw
.
Returns nothing.
NameDefault |
DescriptionType |
---|---|
exit_on_clickTrue |
Whether the window can be closed by clicking anywhere.bool |
skip_initFalse |
For advanced use. Whether to skip calling init when it hasn't been called already.bool |
Expands the L-system string start
according to rules
level
number of times, returning the resulting string.
The draw
function calls this internally. You do you not need to call it unless you want to.
The types and descriptions of start
, rules
, and level
in this function match exactly what they are in the draw
function.
Every non-whitespace printable ASCII character in an L-system string is an instruction as follows:
A-Z Move forward by length step, drawing a line.
a-z Move forward by length step, not drawing a line.
+ Turn positively by turning angle.
- Turn negatively by turning angle.
| Make a half turn (turn by 180°).
& Swap meaning of + and -.
` Swap meaning of uppercase and lowercase.
@ Draw a fill color dot with radius max(2*thickness, 4+thickness).
{ Start a polygon.
} Finish a polygon, filling it with fill color.
[ Push current turtle state onto the stack (position, heading, colors, etc).
] Pop current turtle state off the stack, if not empty.
$ Clear stack.
) Increment turning angle by angle_increment.
( Decrement turning angle by angle_increment.
~ Reset turning angle back to its initial value.
* Multiply length step by length_scalar.
/ Divide length step by length_scalar.
^ Increment length step by length_increment.
% Decrement length step by length_increment.
_ Reset length step back to its initial value.
> Increment line thickness by thickness_increment.
< Decrement line thickness by thickness_increment. Won't go below 0.
= Reset line thickness back to its initial value.
' Reset heading back to its initial value.
" Reset position back to its initial value.
0-9 Change color to the color at this index of colors list.
, Increment current color's 0-255 red channel by red_increment.
. Decrement current color's 0-255 red channel by red_increment.
; Increment current color's 0-255 green channel by green_increment.
; Decrement current color's 0-255 green channel by green_increment.
? Increment current color's 0-255 blue channel by blue_increment.
! Decrement current color's 0-255 blue channel by blue_increment.
# The next 0123456789.,:;!? apply to fill color rather than line color.
\ Stop executing all instructions immediately.
Any characters not mentioned are ignored and have no effect. Many of the instructions are based on Paul Bourke's 1991 L-System User Notes.
The draw(...)
line of code in each example should be used as the middle line here:
from TurtLSystems import draw, wait
draw(...)
wait()
draw('F+G+G', 'F F+G-F-G+F G GG', 5, 120, 10, color=(255, 255, 0), asap=True, png='sierpinski')
draw('A', 'A B-A-B B A+B+A', 5, 60, 10, color=(255, 0, 0), asap=True, heading=60, png='arrowhead')
draw('F--F--F', 'F F+F--F+F', 5, 60, 1.5, color=(0, 128, 255), asap=True, heading=60, png='koch')
draw('F++F++F', 'F F+F--F+F', 5, 60, 1.5, color=(0, 0, 255), asap=True, png='antikoch')
draw('F', 'F F+F-F-F+F', 5, 90, 3, color=(0, 255, 255), asap=True, png='squarekoch')
draw('F', 'F F+G G F-G', 12, 90, 5, color=(255, 0, 255), asap=True, png='dragon')
draw('A', 'A B[-A]+A B BB', 7, 45, 3, color=(255, 128, 0), asap=True, heading=90, png='tree')
draw('X', 'X F+[[X]-X]-F[-FX]+X F FF', 5, 20, 5, color=(0, 255, 0), asap=True, heading=88, png='plant')
Generalized versions of all the examples above and more are available in examples.py which can be imported and run with:
from TurtLSystems.examples import *
sierpinski_triangle()
# sierpinski_arrowhead()
# square_koch_curve()
# koch_snowflake()
# koch_snowflake(anti=True)
# dragon_curve()
# cantor_set()
# tree()
# plant()
# gradient()
Simply uncomment the desired examples and run the file. The exact examples present in this readme can be found all in one place here.