This section is a quick guide to getting started. Install the Luxor.jl package in the usual way:
julia> ] add Luxor
The new (and currently fictitious) organization JuliaFission has just asked you to design a new logo for them. They're something to do with atoms and particles, perhaps? So we'll design a new logo for them using some basic shapes; perhaps colored circles in some kind of spiral formation would look suitably "atomic".
Let's try out some ideas.
using Luxor Drawing(500, 500, "my-drawing.svg") origin() setcolor("red") circle(Point(0, 0), 100, :fill) finish() preview()
This short piece of code does the following things:
makes a new drawing 500 units square, and saves it in "my-drawing.svg" in SVG format.
moves the zero point from the top left to the center. Graphics applications usually start measuring from the top left (occasionally from the bottom left), but it's easier to work out the positions of things if you start at the center. The
originfunction moves the
0/0point to the center of the drawing.
selects one of the 200 or so named colors (defined in Colors.jl)
draws a circle at x = 0, y = 0, with radius 100 units, and fills it with the current color
finishes the drawing and displays it on the screen
In case you're wondering, the units are points (as in font sizes), and there are 72 points in an inch, just over 3 per millimeter. The y-axis points down the page. If you want to be reminded of where the x and y axes are, uses the
:fill at the end of
circle is one of a set of symbols that lets you use the shape in different ways. There's the
:stroke action, which draws around the edges but doesn't fill the shape with color, and you might also meet the
:none actions. You can usually supply these either as an argument or using the keyword argument version, eg
We want more than just one circle. We'll define a triangular shape, and place a circle at each corner. The
ngon function creates regular polygon (eg triangles, squares, etc.), and the
vertices=true keyword returns the corner points rather than draws the shape - just what we want.
Drawing(500, 500, "my-drawing.svg") origin() setcolor("red") corners = ngon(Point(0, 0), 80, 3, vertices=true) circle.(corners, 10, action=:fill) finish() preview()
Notice the "." after
circle. This broadcasts the
circle() function over the
corners, drawing a 10-unit red filled circle at every point.
The arguments to
ngon are centerpoint, radius, and number of sides. Try changing the third argument from 3 (triangle) to 4 (square) or 31 (traikontagon?).
To create a spiral of circles, we want to repeat this "draw a circle at each vertex of a triangle" procedure more than once. A simple loop will do: we'll rotate the drawing by
i * 5° (
deg2rad(5) radians) each time (so 5°, 10°, 15°, 20°, 25°, and 30°), and at the same time increase the size of the polygon by multiples of 10:
Drawing(500, 500, "my-drawing.svg") origin() setcolor("red") for i in 1:6 rotate(i * deg2rad(5)) corners = ngon(Point(0, 0), 80 + 10i, 3, vertices=true) circle.(corners, 10, :fill) end finish() preview()
The Julia colors are available as constants in Luxor, so we can make two changes that cycle through them. The first line creates the set of Julia colors; the
setcolor function then works through them.
mod1 (get the
nth element of an array) is the 1-based version of the
mod function, essential for working with Julia and its 1-based indexing, such that
mod1(4, end) gets the first value of a four element array (whereas
mod(4, end) would fail, since it returns 0, and
colors is an error).
using Colors Drawing(500, 500, "my-drawing.svg") origin() const colors = (Luxor.julia_green, Luxor.julia_red,Luxor.julia_purple, Luxor.julia_blue) for i in 1:6 setcolor(colors[mod1(i, end)]) rotate(i * deg2rad(5)) corners = ngon(Point(0, 0), 80 + 10i, 3, vertices=true) circle.(corners, 10, :fill) end finish() preview()
The flat circles are a bit dull, so let's write a function that draws the circles as 'particles'. The
drawcircle() function draws lots of circles, but each one is drawn with a slightly smaller radius and a slightly lighter shade of the incoming color. The
rescale function in Luxor provides an easy way to map or adjust values from one range to another. Here, numbers between 5 and 1 are mapped to numbers between 0.5 and 3. And the radius is scaled to run between
radius/6. Also, let's make them get larger as they spiral outwards, by adding
4i to the radius when called by
function drawcircle(pos, radius, n) c = colors[mod1(n, end)] for i in 5:-0.1:1 setcolor(rescale(i, 5, 1, 0.5, 3) .* c) circle(pos + (i/2, i/2), rescale(i, 5, 1, radius, radius/6), :fill) end end Drawing(500, 500, "my-drawing.svg") origin() for i in 1:6 rotate(i * deg2rad(5)) corners = ngon(Point(0, 0), 80 + 10i, 3, vertices=true) drawcircle.(corners, 10 + 4i, i) end finish() preview()
This is looking quite promising. But here’s the thing: in a parallel universe, you might already have made this in no time at all using Adobe Illustrator or Inkscape. But with this Luxor code, you can try all kinds of different variations with almost immediate results - you can “walk through the parameter space”, either manually or via code, and see what effects you get. You don’t have to redraw everything with different angles and radii...
So here's what a pentagonal theme with more circles looks like:
Drawing(500, 500, "my-drawing.svg") origin() for i in 1:12 rotate(i * deg2rad(1.5)) corners = ngon(Point(0, 0), 10 + 12i, 5, vertices=true) drawcircle.(corners, 5 + 2i, i) end finish() preview()