Sankey Diagram Generator Code
I’ll add a brief rundown of how it works later, but for now, you can download the code here.
I’ll add a brief rundown of how it works later, but for now, you can download the code here.
UPDATE:
Wow, did I overthink this. No need for all the silly math, just take the distance from the point to the center of the circle, and compare that to the radius. Duh. For humility’s sake, the original post is below.
—
(Old post)
That is the question I asked myself a few days ago. And here is the answer (my apologies for the poor formatting, I need one of those code display plugins…):
/**
* Determines whether or not a given point lies
within a circle
* @param circleX The X value of the center
of the circle
* @param circleY The Y value of the center
of the circle
* @param radius The radius of the circle
* @param ptX The X value of the point
to be checked against the
circle
* @param ptY The Y value of the point
to be checked against the
circle
*/
public static function isWithinCircle( circleX:Number,
circleY:Number, radius:Number, ptX:Number, ptY:Number
):Boolean
{
var theta:Number = Math.atan2( circleX - ptX,
circleY - ptY );
var magnitude:Number = ( ptX - circleX ) /
Math.cos( theta );
if( Math.abs( magnitude ) > radius )
return false;
else
return true;
}
Here’s how it works: The formula to find the point (x, y) on the circumference of a circle with a center (a, b) is a = x + r cos ? and b = y + r sin ? where r is the radius of the circle and ? is the angle in radians from the center point at which the outer point lies.
Since I already know the location of both points and the radius of the circle, it’s pretty simple to fill in the gaps. I replaced r (for radius) with m (for magnitude) and then solved for m. The one last thing we need is the angle - I did a quick search and found that the angle between two points can be found using atan2 (not that I have any clue what that actually does…). That formula is ? = atan2(dX, dY).
Now when I plug in the points, I can check the value of m against the radius of the circle. If m < r, the point is inside the circle. Otherwise, it is outside. I’m no math expert so I can’t say 100% that this is the correct or the easiest/least processor intensive solution to this problem, but it has worked so far for me.
For my final project in Physical Computing, I’m making a real-life Mac OSX dock, with little Sculpey icons that you can use to open and close programs.
First some pictures: the outside, the inside and the icons.



It works by measuring the values of resistors that I glued on to my icons. Each pair of brass washers coming out of the box acts as a switch that can only be turned on by putting an Icon on top of it. Any icon can be placed on any spot in the dock, which completes the circuit. A wire leads to the analog inputs on the Arduino board, which reads the value and then sends out a character over the USB serial port. Each icon has a unique character for it being placed on the dock and for it being removed from the dock.
Reading those serial calls and having them control the applications was harder than I expected. My first plan was to use ASProxy, a program which runs different AppleScripts based on a character received over serial. Sounds perfect, but it didn’t work with how I had coded my handling of the circuit. It seems that to get good results from ASProxy, you have to write the character to the serial port often over many calls to Arduino’s loop() function. In my program, I only write to the serial port once, and I have a hefty delay between loops so that brief connection outages won’t produce odd results (for example, if someone knocks the icon off but then quickly places it back on. Magnets are going to be my next solution to this).
The next solution was to try and have Processing handle calling AppleScript functions. That led me to this Processing hack which doesn’t seem to work anymore. Processing didn’t like having to import that library - but there is a solution to this! Gotta love the Processing forums. You can call AppleScript by using shell scripts, as described here.
I still have a few problems to fix before this works perfectly. It seems that Processing is receiving serial calls even after I have placed and removed an icon. For example, if I place my iChat icon on and take it off, it works fine, but then will continue to open and close iChat. So I need to look into where those calls are coming from (using the extremely useful ZTerm, which has made many things in this process much easier). Also magnets would be a nice touch, so I will figure out a way to have them as well.
For the past 4 months now, I have been working on Sensophoria, my final team project at RIT. I invite you to check out that project’s blog here. I will start to post more about it on this blog once the project is done - time is of the essence right now!
My first project for Physical Computing was to find a creative way to turn an LED on and off using Arduino. A while ago, I said that the only way I’ll use Twitter (which I think is beyond pointless) was if I could hook it up to our cat’s litterbox and have it “Tweet” every time the cat takes a poop. An LED would light up to signal “the litterbox is occupied” or start flashing to signal “warning: it may smell awful.” And that’s exactly what I did!
I had first planned to install an ultrasonic sound emitter inside the litterbox to detect if there was something inside. When I went to Jason to look through his box-o-sensors, however, I found the flex sensor which was not only much easier to use than the ultrasonic emitter, but it would be much easier to code for as well. The flex sensor outputs a number which tells me if it is bending one way or another.
Once I had wired up the board, I took to writing the code. The Arduino code checks three times a second to get the value of the sensor. If it is bending into the litterbox, it signals the LED to turn on. If it is bending out of the litterbox, it tells the LED to flash for a few minutes. The Processing code is responsible for posting the Twitter updates, which works like this: the Arduino board is able to broadcast information via the USB port back up to the computer, which Processing listens for — this is called a serial event. Depending on what the event parameters are, I can tell which direction the sensor is flexed in and post the appropriate tweet using a nifty library called JTwitter. Here’s a screenshot of the programs running on my laptop (technically, Arduino doesn’t have to be open for it to work, but it looks cool with them both there):
And here is a picture of the installed “device:”
If you’re interested, you can follow our beloved cat Reptar on Twitter here.
UPDATE: I released the code, get it here.
It was more fun than I thought to read through the entire stimulus bill, and even more so to do it again, with a different version, when the bill was signed into law. Fortunately, I stumbled across the website stimuluswiki.com, which made the second readthrough considerably easier. After turning all the numbers into XML, I ran it through Processing, fixed whatever errors I had (including an extremely perplexing error involving Processing not liking my XML file generated in FlashDevelop, but having no problem with the exact same code copied and pasted into Dreamweaver) and went to the printers. I’ll take a picture of the print itself later, but for now you can click on the image above for the whole thing or see some actual-size details below.
The unfortunate thing about choosing stimulus package (officially the American Recovery and Reinvestment Act of 2009) as my dataset is that it gets updated quite frequently. So when I started gathering data, the latest version was the one passed by the House. Now the latest version is the one passed by the Senate, and soon it will be the one signed into law. So I stuck with my original version, which means eventually I’ll have to go back in and find whatever changes have been made. The good news is that the generator works like a charm! There are some design obstacles for me to overcome: a more graceful way to handle the text will be necessary, and the overlapping branches aren’t exactly what I wanted the diagram to look like. I’m swiftly converting all of my data to XML, but here is what I have so far: the Depts. of Agriculture, Commerce, Defense and Education.
Fourth time’s a charm! It took a while and a lot of mistakes, but I have my Sankey Generator working with a theoretically infinite number of XML nodes. Here’s how it went down.
While version 0.2 looked exactly how I wanted to, it didn’t work exactly how I wanted it to. It ran through the values, generated all the arrays I needed for the drawing, and plotted them accordingly. However it didn’t keep track of values like where each branch ends, which are very important if I wanted to plot a sub-level (which I did). I knew that I would need to use some sort of recursion to achieve the handling of infinitely-nested XML values, so I decided to rewrite my code from scratch to make it completely recursive. This was version 0.3. It read through the XML file as it is written, line by line, checking for any child nodes before moving on to a sibling node. This made quick work of handling an infinite amount of data, but I encountered a new problem: because it went to children before going to the next sibling, I again could not keep track of the end position of each branch. So once I ran through all the children of a node and needed to draw the next sibling, I would need to get the coordinates of the end of the parent node. My code quickly became cluttered with a ton of offsets and confusing numbers, driving me crazy! I am no fan of ugly code, for one, but most importantly, this wasn’t working. I solved this by creating a middle ground, a combination between recursive and level-by-level XML handling.
In version 0.4, I created a class called BranchGroup. BranchGroup takes three parameters:
It is also responsible for performing two functions:
And voila! Now an infinite number of values with an infinite number of children can be drawn in beautiful Sankey form. My next task is to go through some data (I have chosen Obama’s economic stimulus bill, which so far has been a thrilling read), put it into XML and see how my program handles it. I anticipate having to make a few tweaks to make sure that branches don’t cross over and node labels show up properly. That’s all for now!
Here is the next step forward in my Sankey diagram generator. While it is still far from a finished product, it actually looks like it’s supposed to, which is quite rewarding! Quite simply, I take the point in the middle of each trunk’s Y axis, map all of those values to a larger scale (to create the fanning out effect) and draw a bezier curve from the original point to the end point.
The curves are looking weird in a few spots, for instance with the largest values at the top, it appears to be more of a bulge than a curve. This may just be a matter of giving the curve more room to breathe on the X axis. Eventually I will need to come up with a nicer way to display the monetary values as well.
My next task is to gather more detailed data (specific Federal grants, for example), and draw those on to the graph as well. This should prove more of a challenge, but most of that code is already written.
I took part in Reporter’s (RIT’s campus magazine) Cover Challenge for their crowdsourcing issue, due out later this month. It’s like Layer Tennis, but with more than two people, and for magazine covers. That’s my cover, up above! I made it with Processing and Photoshop. Check out the link to see all the other covers that have been made thus far.