Adding Julia’s Polymorphic Dispatch To My Plotting Library (Part 4)
By: Emmett Boudreau
Tags: Programming, Data Visualization, Data Science, Julia, Algorithms

Adding Julia’s Polymorphic Dispatch To My Plotting Library (Part 4)

The methodology struggle!

In the previous articles, I created a coordinate parser and a functionally object-oriented (I realize how bonkers that sounds) system for transmitting meta-data from objects into a final object that looks a little something like this:

Since then, I have changed only one thing about the module as a whole. The module now exports the functions rather than including them from other modules. So now using the module works the same way that it has in the notebook with the code, for example:

As apposed to:

But after getting these exports done, a thought crossed my mind. Obviously we can plot an X and a Y, but what about comparing data? After-all, most of the time you want to scatter-plot some data you are comparing more than one X, not just visualizing the position of a single X. To change that, I plan to utilize DataFrames, as Lathe is already added as a dependency in the Project.toml; and Lathe has DataFrames.jl as a dependency, meaning that anyone using Hone will likely already have DataFrames on their computer.

There are two main ways that we could approach this. One way is not optimal for the end-user, and is far easier. However, the other way will be a bit more difficult but will make the package better in the long run. I decided to go with option one.

I’m kidding…

Typically in a similar programming language like R or Python, we would have to check the types coming into the function with a conditional, like this for example:

This isn’t such a big deal and reminds me of main loop event programming where you constantly have to check the condition of flags to execute anything, otherwise, it will execute at every tick of the processor, which is kind of funny to bring up. Fortunately, since we are programming in Julia, we can be better than that. We can do so by using Julia’s multiple dispatch, and we can start by writing two functions that need to handle the two different types.

Now we just add these two neat little lines to apply these methods as properties of the struct:

And now when we call it with our two types:

The functions are ran accordingly per type.

We can apply this idea into Hone by making a new Scatter function that will handle a Data-Frame rather than Arrays. I renamed our old Scatter function to _arrayscatter, and our new one will be _dfscatter. I use this naming scheme with the underlines out of personal preference because it helps me to differentiate between end-user functions and back-end functions that the user will never see, though it isn’t necessary, I do think it’s important to stay consistent.

And now we just add our dispatch line:

Note that I had to first load DataFrames.jl into the session to use the DataFrame type. Another thing to note is that y has the type assertion of Symbol, rather than Array like you might have expected, this is because we are assuming that the array we would like to use as our Y is inside of the data-frame, so we can call it like so:

x[y]

oddly enough.

Now we can construct a data-frame just to demonstrate that everything is indeed working:

df = DataFrame(:one => [1,5,2,3], :two => [8,4,5,3], :y => [5,6,2,3])

And when we pass it through our function:

So the dispatch is working, but we still need to add logic to the plotting for the data-frame function. To do this, I’m going to first abduct the code from the regular scatter function, but then just duplicate the coordinate parser so that it parses through both X’s separately. The result we are looking for should be four additional points on a scatter-plot for a total of eight. So first I’ll show you the result, and then dive into the refactoring I had to do:

For the explanation, I’m going to go line by line because there is a lot here. Firstly, in the scatter function where the maximums and minimums are obtained; I had to move the calculation of the maximum of X into the iterative loop because this time we were looping through different arrays with different maximums. However, I did retain the Y’s original position:

function _dfscatter(x,y,shape,debug=false)

topy = maximum(x[y])

Next, the loop that needs to be moved that changes all of the coordinates to percentages in the original function into the loop (as it should be.)

Aside from that, the actual parsing is moved to the inside of the loop that goes through the columns. Now what is likely a very obvious flaw is that there is no way to distinguish the two X’s from one another on the coordinate plane,

so let’s change that.

The first step in this process will be to make our “ shape” parameter an Array in the type assertion of our polymorphic dispatch, like so:

And now we’ll simply add a counter to our loop, starting at zero and progressing until the looping is complete. This will help to determine our position in the data-frame, though I might change this in the future to use the indexes of the columns instead.

Now you would think that if we tried to use our function with a single shape, it would no longer work, but this simply isn’t true and it will still work fine — Julia will just pretend it is a single dim array, which I was actually surprised about. This reveals a new issue, however, which is the issue of contexts I didn’t even think about, as fill color can only be declared once per context, but I will certainly be elaborating on that in the next article because there is something else I wanted to get to in this one!

Adding a new shape.

Fortunately, I made this incredibly easy for my future self, and we can start creating our new shape by simply ripping our circle function, and I am going to rename it rectangle.

As I assumed, I was correct and all that this entailed was adding the parameters for the rectangle and renaming the function, nothing complicated whatsoever. What’s great is now we can go full

circle.

Get it? Well anyways, we can use the shapes rather than the color to distinguish the two columns from one another.

Look on the bright side, at least that’s not a lot of text or anything.

Now let’s pass those shapes through our _dfscatter function!

I’ll let Spongebob explain how that feels: