# The beginning of Javis.jl

Creation date: 2020-08-04

Tags: julia, javis, visualization, animation

I'm back! Sorry that I didn't blog for more than two weeks. I might have gotten a bit too much into the streaming world and programmed more than blogging about it. This post starts with some housekeeping and then explains the newest project I'm working on. Feel free to jump to the point you are most interested in.

## Housekeeping

The last post here was about visualizing kinda random numbers :D Visualizing digits. It might be the one that brought me to building Javis but more on that later.

I'm currently mostly working on two projects:

ConstraintSolver.jl where I try to build a constraint solver from scratch in Julia. I started with some refactoring lately and streamed about it via Twitch. The videos are saved on YouTube. The refactoring is still going and I probably will write a post about that once it's done just to have a better structure of the outcome. Streaming is unstructured and hard to watch later I suppose. I'm still trying to figure out the best way to combine my possibilities to teach julia.

The new project is Javis.jl which I explain in the next section.

Sometimes I work on Juniper.jl as it is my small baby. It's my first project in Julia and the most used one I've built up til now. I mostly do bugfixes for it at the moment but might come back to it to add some new awesome features.

## Javis.jl

Okay what is Javis?

Javis stands for Julia Mathematical visualizations and animations. (Currently at least 😄)

A small side note maybe: The Juniper package I was talking about was called MINLPBnB.jl which is the worst name possible, so I might have gotten better at naming things. I have to say it's very easy to see what the package does: Mixed Iteger Non-Linear Programming using Branch and Bound. Well, some folks told me it should have a proper name... We debated to call it Bacon.jl and I can't remember what it stands for.

... The thread apparently it was for "Branch Optimization Nonlinear". Just saw that I suggested BOREDOM as well. Oh man fun times...

Any way I liked Javis this time and just tried to find out what it might stand for.

To answer the actual question:

Javis tries to make it as easy and extensible as possible to create small animations like this one:

I'll show the code for it later. 😉 In general I want to have a simple way to animate all the ideas that might get into my head. Just some examples

• Visualizing linear algebra concepts easily

• Animate puzzles for my ConstraintSolver

• Explore math concepts

### Standing on the shoulders of giants

Normally I try to build things from scratch (in a high level programming language 😄). This time I'm more aware than ever that I'm standing on the shoulders of giants.

It is of course built with Julia which should be no surprise. BTW a new version (v1.5) is official now 👍

Besides that it is highly dependent on the awesome package Luxor.jl which is used for all the drawing onto a canvas. It provides simple functions like line, circle and so on but also gave rise to the way we do animations.

Luxor.jl is itself built using Cairo.jl which is a wrapper around the C library Cairo.

If you're interested in 2D graphics, you should definitely check out the awesome Luxor Tutorial.

### State of Javis

Edit: 12.08
We're in rapid development so this is already out of date. At some points I have an edit like this one to show when something changed. We haven't released v0.1.0 yet so you don't get deprecation warnings if something fails 😕

You might be interested in the current state of Javis.jl as the documentation is very sparse (or non-existent for stable) and the README doesn't show anything especially entertaining 😄

Me an my fellow Julian and streamer Jacob Zelko started this project about two weeks ago. Furthermore, I was away for a week so everything is very new.

The basic functionality

• $$\LaTeX$$ text which is not possible in Luxor.jl

• Translation and rotation of objects

• Objects depending on others (quite basic as of now)

• Very basic morphing between two shapes

Before I give a view into the future you might want to see some code, right?

### How to do the animation from above?

I think we should start with the very very basics before I show you the 40 lines of code.

using Javis, Luxor
Edit: 12.08
Now it's only using Javis as we started to reexport everything that Luxor does and change some methods to work in our favor 😃

We normally need both of the packages as we want to do some animations (Javis) and want to do some drawing (Luxor).

I don't like to work in the global scope so let's create a function:

function dancing()
video = Video(500, 500)
javis(video,
[
...
]
,tempdirectory="test/current/images", deletetemp=true, creategif=true, pathname="test/current/dancing_circles.gif")
end
Edit: 12.08
I promise I write another post when we release v0.1 :) deletetemp and creategif don't exist anymore.

It has quite a few parameters to create a simple gif out of it, so I think this needs improvement but that's for another day.

First of all we create our video object which is nothing more than a struct. The object sets the width and height in pixel of the video and stores information in between but that is of no concern to the user.

Then we have our javis function which is the main function of our project. It takes at least two arguments: the video and a list of actions that shall be performed during the video. The ... is just a placeholder for now.

We have a list of keyword arguments:

• tempdirectory stores the images (yes we create an image for each frame and combine them later)

• deletetemp means that all images are destroyed after we created the gif

• creategif yes we want to create a gif and not only having a list of images

• pathname the gif should be stored here

Okay now to Action.

Let's create our first "Animation":

function ground(args...)
background("white")
sethue("black")
end

function dancing()
video = Video(500, 500)
javis(video,
[
BackgroundAction(1:70, ground)
]
,tempdirectory="test/current/images", deletetemp=true, creategif=true, pathname="test/current/dancing_circles.gif")
end

The ground function sets the background to white and the paint brush color to black.

Why do I need the args...? I'm glad you ask. Each user function gets three arguments video, action, frame where the first is the Video struct, the second is the Action struct and frame is just the current frame number. They are irrelevant for the background such that we don't need to write them down explicitly. "Unfortunately" we need to write args... such that Julia actually knows that we have a method that accepts those three arguments. The ... basically stands for as many arguments as you want.

⚠ Note
sethue is the same as setcolor but doesn't mess with the opacity

More interesting is the BackgroundAction(1:70, ground) which has just two arguments here:

• frames a range of frames it is applied to.

• func the function that is called for each frame

I hope it is clear what you can expect from the 70 frames we just created 😉

Feel free to click to see the boringness

Okay it's time to actually draw something with adding another action:

...
BackgroundAction(1:70, ground),
Action(1:70, (args...)->line(O, Point(25, 25), :stroke), Translation(O, Point(0, 100)))
...

This time we define an Action instead of a BackgroundAction which basically means: Everything in this action stays in the action and is not exposed to the outside world. You might wanna call it the Vegas of actions. Sorry for the bad joke...

There are some new parts in this:

• An anonymous function with the -> syntax.

• The line function from Luxor which takes in two points and an action

• O is the same as Point(0, 0) and stands for origin (which is in the center of the canvas)

• :stroke means that we want to actually draw the line which is not the default and might be confusing

• Translation from the origin to the point (0,100)

Some more information before you have a look at the spoiler.

The canvas has its origin in the center as mentioned but it also has the y-axis going down instead of up. I'm not sure whether we want to change that for Javis.

Did you expect this?

So the Translation is animated by interpolation between the start and end translation. In the future we will make it possible to use easing functions to change this behavior.

Additionally, the Translation translates the plane such that drawing the line from (0,0) to (25, 25) results in drawing it from (0, 100) to (25, 125) in the last frame.

I hope that it makes sense so far.

Okay how do I draw circle that is moving down at the same rate by defining a new Action?

...
BackgroundAction(1:70, ground),
Action(1:70, (args...)->line(O, Point(25, 25), :stroke), Translation(O, Point(0, 100))),
Action(1:70, (args...)->circle(Point(-25, 0), 10, :fill), Translation(O, Point(0, 100)))
...

Simple, right?

Okay this is the boring way of doing it but let's have a look at the circle function first.

The circle function takes a Point a radius and an action. For the action I chose :fill instead of :stroke this time.

For a bit more fun we want to define the first action a bit differently using a named function.

function draw_line(args...)
line(O, Point(25, 25), :stroke)
return Transformation(O, 0.0)
end

and then:

...
BackgroundAction(1:70, ground),
Action(1:70, :line, draw_line, Translation(O, Point(0, 100))),
Action(1:70, (args...)->circle(pos(:line) .+ Point(-25, 0), 10, :fill))
...

This adds quite some more complexity but hopefully it's not too hard to understand and it is a very powerful tool.

Action(1:70, :line, draw_line, Translation(O, Point(0, 100))),

is not an anonymous function anymore but it also has a name :line as the second argument.

Furthermore, the function now return something:

return Transformation(O, 0.0)

It does return the same position (the origin, tail of the line) every time. The second argument is the angle of the transformation which is set to 0.0 as we don't use it. There is already a PR to be able to use return O instead 😉

Edit: 07.08
The PR got merged such that you can write return Point(x,y) now instead of using a Transformation.

Now in the circle action:

Action(1:70, (args...)->circle(pos(:line) .+ Point(-25, 0), 10, :fill))

we have access to the position of the line with pos(:line) and we removed the Translation.

The pos(:line) is actually not the origin all the time as it had its own Translation. Javis "assumes" that you're interested in the actual canvas position of :line and not the one that is returned directly. Internally the position is therefore converted into the global coordinate system.

This is an important concept so let me try to explain it in different words 😉

• You can use some kind of variable which is a Symbol like :line to be able to save whatever you return in that function.

• If you return a Point or a Transformation it will be automatically converted to global coordinates.

• You can access the saved position with pos(:line) or whichever Symbol you have used.

I think you know what happens

### Do you show the code now?

Okay yeah I think I can finally explain the code for the animation I showed in the beginning:

function dc()
p1 = Point(100,0)
p2 = Point(100,80)
path_of_blue = Point[]
path_of_red = Point[]

video = Video(500, 500)
javis(video, [
BackgroundAction(1:70, ground),
Action(1:70, :red_ball, (args...)->circ(p1, "red"), Rotation(0.0, 2π)),
Action(1:70, :blue_ball, (args...)->circ(p2, "blue"), Rotation(2π, 0.0, :red_ball)),
Action(1:70, (video, args...)->path!(path_of_red, pos(:red_ball), "red")),
Action(1:70, (video, args...)->path!(path_of_blue, pos(:blue_ball), "blue")),
Action(1:70, (args...)->rad(pos(:red_ball), pos(:blue_ball), "black"))
], tempdirectory="test/current/images", deletetemp=true, creategif=true, pathname="test/current/dancing_circles.gif")
return video
end
Edit: 07.08

You don't need to define the frames every time anymore. It's possible to define it for BackgroundAction and define later actions like:

Action(:red_ball, (args...)->circ(p1, "red"), Rotation(0.0, 2π))

without defining frames. Then it will use the same frames as the previous action.

First of all I just defined some points at the beginning to change them in an easier way.

The functions itself are not that interesting:

• circ just creates a circle with some default radius and sets the color with sethue and returns the center.

• path! takes a list of points and a new point and draws them as circles

• rad draws a line from the first to the second point with some color

function circ(p=O, color="black")
sethue(color)
circle(p, 25, :fill)
return Transformation(p, 0.0)
end

function path!(points, pos, color)
sethue(color)
push!(points, pos)
circle.(points, 2, :fill)
end

function rad(p1, p2, color)
sethue(color)
line(p1,p2, :stroke)
end

Let's get back to the actions:

BackgroundAction(1:70, ground),
Action(1:70, :red_ball, (args...)->circ(p1, "red"), Rotation(0.0, 2π)),
Action(1:70, :blue_ball, (args...)->circ(p2, "blue"), Rotation(2π, 0.0, :red_ball)),

Instead of using Translation we now use Rotation which takes in either two or three arguments.

• start rotation

• end rotation

• center of the rotation (default is O)

Here we use :red_ball as the center of rotation for the :blue_ball.

• The red ball rotates around the origin with a radius of 100 as it starts at Point(100, 0)

• The blue ball rotates around the red ball with a radius of $$\sqrt{100^2+80^2} \approx 128$$ as it has the initial start position of p2 = Point(100, 80) is rotated around the start position of p1 = Point(100, 0)

Action(1:70, (video, args...)->path!(path_of_red, pos(:red_ball), "red")),
Action(1:70, (video, args...)->path!(path_of_blue, pos(:blue_ball), "blue")),

with path!

function path!(points, pos, color)
sethue(color)
push!(points, pos)
circle.(points, 2, :fill)
end

just adds the new position of either the red or blue ball with pos to a list of points and draws the path by just drawing a circle for each position of points.

This is done with the broadcast dot notation circle..

The last action:

Action(1:70, (args...)->rad(pos(:red_ball), pos(:blue_ball), "black"))

just draw the line between the red and blue ball to see that the radius is really not changing.

### View into the future

There are some things that are on the list:

• ability to draw vectors for a small linear algebra intro video

• do some nice animations of matrices like the highly requested feature: transposing a matrix

• I'm really interested in doing nice morphing between shapes

• Make it easier to define frames

• Easing functions for more interesting animations

• ...

There is so much more to do! If you want to get involved: Just reach out.

Even after I've published the poster just a few days ago there are a lot of new changes. You might just wanna check out the repository from time to time or watch it. (You might get quite a few E-mails). GitHub: Javis.jl

See you next time :)

Thanks for reading and special thanks to my 10 patrons!

List of patrons paying more than 4$per month: • Site Wang • Gurvesh Sanghera • Szymon Bęczkowski • Logan Kilpatrick Currently I get more than 20$ per month using Patreon and PayPal.

For a donation of a single dollar per month you get early access to the posts. Try it out at the start of a month and if you don't enjoy it just cancel your subscription before pay day (end of month).

I'll keep you updated on Twitter OpenSourcES as well as my more personal one: Twitter Wikunia_de