generating fractals

Today we'll discuss a general method to produce 2d images of fractals, and a python implementation



Before we draw fractals, let's make sure we can draw a circle, a fundamental mathematical object, for if we can't do that, then we will have a hard time trying our hand at something more complicated.

A circle, is a collection of points, all equidistant from a center point, each point on the circle has no physical size, there are infinitely many points on the circle, and when thought of together it defines a curved line in space.

Our goal is to use a screen to represent a circle, we'll represent it by coloring the background of the screen black, and drawing the circle with white pixels.

from pixel to point

Given a pixel (a, b)px on the screen, we'd like to associate this with a point on the plane, with that we can determine if the point resides on the circle and if it does, we may color that pixel white.

screen annoyances

show details

When we talk about a cartesian plane, we usually think of 0 residing in our center of vision, and then having four quadrants around this, using this system the circle we spoke of earlier would be in the center of our view.

Contrary to this, most screens say that the pixel (0, 0)px is at top left of the screen, and the bottom right as of the screen has the pixel (screen_width, screen_height)px therefore moving donwards actually represents an increase in the y value, which is contrary to the cartesian plane.

With the above said, if our mapping from a pixel to a point was (a, b)px to (a, b), then the central point (0, 0) on the cartesian plane would be moved up to the top left corner, which wouldn't make sense as if we were able to draw our circle with pixels on the bottom left of the circle would be visible.

center it

show details

A way to fix this would be to make sure the central pixel (screen_width/2, screen_height/2)px is mapped to the point (0, 0), as with this we would be able to make sure that the central pixel refers to the central point of the cartesian coordinate system.

And so a new mapping could be (a, b)px to (a - screen_width/2, b - screen_height/2), which guarentees when a = screen_width/2 and b = screen_height/2 that we get back (0, 0). Additionally, with this in place, the top left pixel of the screen maps to (-sw/2, -sh/2), the top right maps to (sw/2, -sh/2), the bottom right maps to (sw/2, sh/2) and the bottom left maps to (-sw/2, sh/2), thus the entire width of the cartesian plane this maps into is sw, and the height is sh. For ease of use, we will denote this map by center( (a, b)px ), so that center( (sw/2, sh/2)px ) = (0, 0)

scale it

show details

Now with this system we can see that depending on the resolution of your screen, the section of the cartesian plane that your screen refers to is either larger or smaller. Since we don't want to discriminate between our newer and older computers we can divide the x coordinates by sw and the y coordinates by sh, so given a pixel (a, b)px, we can center it to get (c_a, c_b) and then divide (c_a / sw, c_b / sh). So that now this point is constrained within the section of the cartesian plane with 4 corner points (-1/2, -1/2), (1/2, -1/2), (1/2, 1/2), (-1/2, 1/2) (which outlines a box of side-length 1)

invert y axis

show details

Now all screens we use will be referring to the same section of the cartesian plane, make sure that their central pixel refers to (0, 0), but there is one issue, based on our last paragraph, if we move from the center of the screen to the top of the screen, our y value will go from 0, to -1/2. This is an issue because in the cartesian plane, as we move up, the y value is positive and is increasing. Therefore we can first center our pixels, then scale them, and finally flip the y axis.

aspect ratio

show details

If you've noticed the area of the plane that our screen refers to is a square, but our screen in real life is probably not a square, usually they are rectangles (I haven't yet seen a circular monitor, but I think that would be fun too). What this means is that if we consider a rectanglular screen, as it gets mapped into a square, the resulting pixels pixels we light up will now illuminate an ellipse rather than a circle. So let's account for this in our pixel to point mapping.

Since we know the aspect ratio of our screen is sw:sh in simplest form, we can make it into a ratio where we allow fractions like 1:sh/sw, meaning that for 1 pixel horizontally we'd get sh/sw pixels vertically, since we can't split pixels this isn't possible, but it means that we can multiply the y component by sh/sw after inverting the y axis, which would make sure that the region on the caresian plane that our screen is mapping into has the same shape as our monitor


show details

Finally if you want to zoom in, then we multiply the aspect corrected point by a constant. This zooms in around the (0,0) point because

our fixed up screen

Note that the above procedure works because of the fact that we put (0, 0) at the center, these transformations don't work as expected when the central point is not (0,0) for example the conjugate wouldn't work correctly as we're trying to flip y axis around the central point

Whenever we have a screen that works in the standard way, we need to remember to Center, Scale, Invert and tweak the Aspect Ratio. In otherwords, if you want to fix your screen you're going to need C-SIAR's, like scissors?