Galileo Galilei was said to have said: “[The universe] stands continually open to our gaze, but it cannot be understood unless one first learns to comprehend the language in which it is written. It is written in the language of mathematics, and its characters are triangles, circles, and other geometric figures, without which it is humanly impossible to understand a single word of it; without these, one is wandering about in a dark labyrinth.”
Galileo was only partially right—something about this quote is off. If you ever see a rectangle, square, triangle, or even a straight line in nature, it was probably machine-made or human-made. Benoit Mandelbrot said it better: “Clouds are not spheres, mountains are not cones, coastlines are not circles, and bark is not smooth, nor does lightning travel in a straight line.”
The shapes of nature have evolved to be efficient. We model them with fractals.
In this lab, we’ll gain an initial understanding of fractal shapes by generating pictures of trees, using a tree-drawing library.
Recursion in images Using an image library RGB Colors
Make sure you are in your virtual environment, because we are going to install a library that can draw trees:
pip install Tree
Let’s write a program to use this library. It’ll be basically the example program straight from the library’s PyPi page. So mkdir a lab12 folder and cd into it. Create the file tree.py with the following code:
from math import radians from Tree.core import Tree from PIL import Image tree = Tree((0, 0, 0, -200), [(0.75, radians(-30)), (0.75, radians(30))]) tree.grow(10) tree.move_in_rectangle() image = Image.new("RGB", tree.get_size(), (200, 240, 250)) tree.draw_on(image, (50, 40, 0, 180, 130, 30), (30, 160, 30), 25) image.show()
Run the program with the command python tree.py. You should see a window pop up with a tree in it. If you don’t see anything, make sure you are still in the virtual environment and that you have installed the Tree library. After admiring your work, close the window.

What even is going on with that code? What even do all those numbers mean? Such excellent questions!
It turns out this tree drawing library actually has complete documentation online, explaining the Tree class, its initializers, and its other methods. But still, what do all those numbers mean? Even if you memorized the documentation, it would be really, really hard to make sense of that code. We should be ethical programmers and try to make our code more readable. Let’s add some variables and use keyword arguments to improve the code above:
from math import radians from Tree.core import Tree from PIL import Image background_color = (200, 240, 250) leaf_color = (30, 160, 30) trunk_width = 30 base_trunk_color = (50, 40, 0) small_branch_color = (180, 130, 30) branch_gradient = (*base_trunk_color, *small_branch_color) trunk_length = 200 first_branch_line = (0, 0, 0, -trunk_length) scales_and_angles = [(0.75, radians(-30)), (0.75, radians(30))] age = 10 tree = Tree(pos=first_branch_line, branches=scales_and_angles) tree.grow(age) tree.move_in_rectangle() image = Image.new("RGB", tree.get_size(), background_color) tree.draw_on(image, branch_gradient, leaf_color, trunk_width) image.show()
There are so many parameters to vary here, aren’t there? Experiment with age first, noting that:
age=0 and age=1 the program crashes.age=2 you get a tree with a trunk and two branches, and each branch has two leaves.age=3 you get a tree with a trunk and two branches, and each branch is...a tree of age 2.age=4 you get a tree with a trunk and two branches, and each branch is...a tree of age 3.age=5 you get a tree with a trunk and two branches, and each branch is...a tree of age 4.You see what is going on here, right?
Recursion.
Where exactly is the recursion coded up?You don’t see the recursive calls because they are buried inside the library somewhere, but they are there.
Do you think you can find the code? (Hint: there’s probably a link to the GitHub repo for this somewhere in the documentation. Or use the VSCode File Explorer to dive deep into the env folder. 😮)
Walking through successive values of age from 2, 3, 4, and so on also highlights the way color gradients are interpreted by library. Play around with those a bit, as well as with the trunk width and trunk height.
But wait...how do we understand colors? Why is each color a tuple of three numbers? It turns out this is no accident. Try out this little widget to explore how colors are made from the three primary colors, red, blue, and green:
R 0
G 0
B 0
The R-G-B color model works well, as it mimics the human visual system. We all have three cones in our eyes, one sensitive to red, one to green, and one to blue. Mixing them together allows us to perceive a wide range of colors.
You can also search for an online color tutorial to learn more.
Next, work on varying the branch data, in the scales_and_angles list. The original code has only two branches, each 75% the length of the previous branch, and each angled 30 degrees off the previous branch. You should experiment with different numbers of branches, different scaling factors, and different angles. Note that you can, and are encouraged to, make the branches have different scale factors and angles from each other—that makes the trees more realistic because they’re not so symmetric.
As you experiment, make a note of your favorite tree settings and slack them to everyone else on the private class channel. Or, upload a screenshot of a nice tree and ask classmates to guess the parameters.
[(0.5, radians(-30)),(0.4, radians(40))] with an age of 10 and trunk width of 25 to be kind of Joshua tree like. What do you think? And interestingly, adding the tuple (0.5, radians(2)) to that list, seemed to make a massive change, with a big leaf canopy. What do you think is going on there?
Don’t forget to add, commit, and push. And write a nice README.md describing what you’ve done.
Now it’s your turn. Here are some ideas for you to extend the activities above:
sigma parameter for the Tree initializer but does not say what it does. Play around with that, too. What do you think it means? Are there comments in the source code that indicate its purpose? (Hint: it has something to do with adding some “randomization” to the tree, but (1) how exactly, (2) why would we use it, and (3) what are some decent values for this parameter?)You might want to take a peek at this article in which the author explains the construction of a fractal tree. It’s not crucial to understand what’s going on in detail, but reading the article might give you an intuition of the big picture.
If you would like to dig deeper into exactly what is going on with virtual environments (internal workings, why we need them, and some of the many additional features you get with pip and related tools), there are many online resources that should be easy to find. The Python Tutorial covers them in Section 12 if you are interested.
We’ve covered:
pip installHere are some questions useful for your spaced repetition learning. Many of the answers are not found on this page. Some will have popped up in lecture. Others will require you to do your own research.
age parameter control in the tree drawing code? scales_and_angles parameter in the Tree class? leaf_color, base_trunk_color, and small_branch_color variables.move_in_rectangle method in the Tree class? image.show() method from the PIL library.branch_gradient variable in the tree drawing code?