Blog

  • Sankey Diagram using D3.js Part 2 of 2

    The chart below shows the flows of money to Toronto mayoral candidates in 2006. What follows is a quick explanation and a few observations. Then I follow up with a few short tips on how I got the visualization up and running.

    2006 Toronto Election Contributions
    By Region, Dollar Amounts and Candidate

    [iframe width=”600″ height=”520″ src=”https://zenbot.ca/elections.html”]
    Source: City of Toronto

    Note that I was coding anything ‘Outside Toronto’ to be more specific and got part-way (you can see Kingston and Ottawa as some locations). Basically outside Toronto extends to Mississauga, Oakville and the Golden Horseshoe. It was possible to get more specific but I didn’t for this visualization. ‘Central Toronto’ seems to be not downtown, but includes Yonge/Eglington, etc.

    You can also see that proportionally, Stephen LeDrew received a relatively large amount of corporate donations (the orange links) while David Miller received none. You can also see that David Miller received money, not only from downtown, but everywhere. You can also see that the vast majority of the money is coming from individuals (blue) versus corporations (orange).

    If I were going to push the analysis further, I could get number of donors per candidate. I would also have loved to get 2009, as it is more recent, but like I mentioned in part 1 that wasn’t available through the city of Toronto’s website. I am sure comparing 2006 to 2009 would have been very interesting even if the candidates are completely different.

    To get the visualization working, you not only need the latest D3.js library, but also the sankey.js plugin which should both be included in your header:

    script type="text/javascript" src="js/d3.v3.min.js" charset="utf-8">/script>
    script type="text/javascript" src="js/sankey.js" charset="utf-8">/script>

    Next, I added some in-line styling:


    .link {
    fill: none;
    stroke-opacity: 0.4;
    }
    .link:hover{
    stroke-opacity: 0.6;
    }
    svg {
    font: 12px sans-serif;
    }

    In the main body, you need something to attach the svg chart to. In this case I picked the following:

    h1 id="chart"

    And finally the main bulk of the code. If you run into problems, please feel free to comment, below.

    //a big thank you to Mike Bostock. Most of this code is originally his
    //// modified for the purposes of this demonstration
    var margin = {top: 10, right: 1, bottom: 6, left: 1},
    width = 600 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    var formatNumber = d3.format(",.0f"),
    format = function(d) { return "$" + formatNumber(d); },
    color = d3.scale.category20();
    var svg = d3.select("#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var sankey = d3.sankey()
    .nodeWidth(15)
    .nodePadding(10)
    .size([width, height]);
    ////this colarray is to avoid going into the JSON document to change the colors of the link
    var colarray = {
    'Individual': '17,203,235',
    'Corporation': '252,189,53'
    }
    var path = sankey.link();
    /////////////here is where the sankey should kick in....
    d3.json("js/electionJSON.json", function(election) {
    sankey
    .nodes(election.nodes)
    .links(election.links)
    .layout(32);
    var link = svg.append("g").selectAll(".link")
    .data(election.links)
    .enter().append("path")
    .attr("class", "link")
    .attr("d", path)
    .style("stroke-width", function(d) { return Math.max(1, d.dy); })
    // .style("stroke-width", "100")
    .sort(function(a, b) { return b.dy - a.dy; })
    .style("stroke",function(d) { return "rgb(" + colarray[d.contribution_type] +")"; })
    link.append("title")
    .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.value); });
    var node = svg.append("g").selectAll(".node")
    .data(election.nodes)
    .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
    .call(d3.behavior.drag()
    .origin(function(d) { return d; })
    .on("dragstart", function() { this.parentNode.appendChild(this); })
    .on("drag", dragmove));
    node.append("rect")
    .attr("height", function(d) { return d.dy; })
    .attr("width", sankey.nodeWidth())
    .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
    .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
    .append("title")
    .text(function(d) { return d.name + "\n" + format(d.value); });
    node.append("text")
    .attr("x", -6)
    .attr("y", function(d) { return d.dy / 2; })
    .attr("dy", ".35em")
    .attr("text-anchor", "end")
    .attr("transform", null)
    .text(function(d) { return d.name; })
    .filter(function(d) { return d.x < width / 2; }) .attr("x", 6 + sankey.nodeWidth()) .attr("text-anchor", "start"); function dragmove(d) { d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")"); sankey.relayout(); link.attr("d", path); } });

  • Sankey Diagram using D3.js Part 1 of 2

    Among other things , I’ve been itching to master some D3.js tricks, mainly because the plugin lets you do some pretty gorgeous stuff, and there’s a wide variety of visualizations which are highly customizable. Recently, I finally had a few minutes to try something out. Since my work entails working with Statistics Canada data, or anything to do with start ups in Ontario I figured I would go for something that has nothing to do directly with that world.

    This led me to tracking down some elections donation data from the city of Toronto’s open data repository which was the donor list from the 2006 mayoral election. The title said it included 2009 as well, which sucked me in because that’s what I really wanted to use. I was disappointed when I found out it was only 2006, but figured it was OK because either way I was just playing around.

    The first part of this two-part series will describe how to lay out the data to get it ready for a Sankey diagram. The second part will talk about how I actually got the visualization going in D3.js. The data as it is presented shows each donor, their postal code, and whether they are a corporation or not and (of course) the candidate who received the donation. Sankey diagrams don’t need that level of detail, and I just wanted to show the movement of money from different parts of the GTA (and beyond) and how that money flowed to each candidate. So the first thing you do is you summarize by FSA (the first three digits of the postal code), while keeping the dollar amount, candidate name and type of donor (corporation vs. individual). I don’t really care how you do it: just run a pivot table, or something, just get that dollar amount by FSA.

    Next, get the area names by FSA region from Wikipedia so that you can distinguish different areas in a readable manner. Now you want to present the data in well-formed JSON like this:
    {"nodes":[
    {"name":"Brockville"},
    {"name":"Central Toronto"},
    .....
    ],
    "links":[
    {"source":0, "type": "Individual", "target":26, "value":500},
    {"source":5, "type": "Individual", "target":16, "value":200},
    ....
    ]}

    A quick note here that sankey.js (the library plugin to include with D3.js) is kind of picky and “value” (as above) is pretty immutable.
    Don’t get caught like I did by using “amount” instead of “value”.

    Finally, every single node (both region and mayoral candidate) gets included in the list of “names”. Then the “source” and “target is whomever is on the list of nodes, in order, starting at zero. In the example above, Brockville = 0. So now that you have the JSON explained, just create the JSON file and you are ready to go to part 2.

  • 3Doodler Troubleshooting

    I had the pleasure of backing a project on kickstarter called ‘3Doodler‘ by Wobbleworks. The 3Doodler allows you to ‘print’ in the air by extruding 3mm plastic (ABS or plastic) through the pen-like nozzle of the 3Doodler. So it is a great tool if you are creative and looking to bust out of the two-dimensional world of drawing. Also, it could be handy for certain kinds of repairs, or quick prototyping or 3D sketching of designs.

    If you search on the web for images of 3Doodler you’ll see lots of great images, particularly using Flickr. I kept my expectations in check, because I knew that they were likely swamped with orders by blowing past their $30,000 Kickstarter goal by raising $2,344,134 and that they wouldn’t be able to send me the goodies right away. Nonetheless I received regular updates and felt pretty good that my 3Doodler would arrive, eventually.

    Months later, it arrived, and I tried to stay calm as I opened the box. I had contributed enough to the Kickstarter project that I received extra ABS and so I was all set to start doodling! Descending into my workshop, I figured my family would be protected in case it blew up. After letting it heat up (it is kind of like a sci-fi glue gun in that respect) I inserted some ABS and let ‘er rip.

    After extruding a small amount of ABS (about 4 cm) the motor became more high-pitched and nothing came out. I tried a few times and after putting plastic in and out I consulted their website. I ended up elevating it and was eventually led to a Skype conversation with Max Bogue, who is one of the co-founders. It’s a good sign when the founder wants to get down and dirty and troubleshoot problems on the ground floor.

    We eventually figured that my 3Doodler had two problems (or at least, one definitive problem and another which is likely but merits further investigation):

    1. The fan wasn’t working. That in and of itself was not an immediate problem, but could lead to issues when I get it up and running and really start putting it through its paces
    2. The second thing, which Max will take a look at, is that the wheel is not gripping the ABS tightly enough to pull the plastic through. So, it goes through a little ways, but the moment it meets too much resistance, it can’t really grab and push on the ABS.

    At the end of the call, we resolved that I would send back the 3Doodler and he would fix it and return it. Because of the awesome customer service and that this is a first generation product, I’m pretty optimistic that we can get this sorted out and I’ll be posting my doodles here, shortly. Stay tuned!

  • Maker Sale

    Besides being a very busy graphic designer and mother of two, my wife still manages to find time for a number of creative outlets: She crochets excellent hats, makes art prints and also accessories for your purse or bag (the first two are featured on her Etsy store). Unfortunately, she found there is a lot of ‘liking’ on Etsy of her store, but it is not translating into sales.

    She decided to take the bull by the horns and have some fun in the process by hosting an event at our home. In order to make it more fun, she enlisted the help of some other crafty designers to pitch in with some of their work. She convinced me to unearth some photographic work of my own which I explain in more detail in my metallic c-print blog post.

    Finally, this was a sort of artistic ‘coming out’ for our oldest daughter, Sophie with the official launch of her art cards. Sophie draws over a hundred drawings a week and so we thought it would be exciting for her to have some of her output transformed into colourful greeting cards. Naturally, this was exciting for Sophie as her first experience with selling her work.

    Other participants were Paula Huszagh who did some awesome rings. Finally Joanne Malakassiotis Vekar brought some jewelry as well, including necklaces and bracelets. You can find her store on Etsy here.

    Katherine opted for a Facebook invitation, because Etsy is excellent for what it is, but it doesn’t get just to her friends in the same way as Facebook. In hindsight, Evite.com has a better reminder capability, so that might be something to use for next time.

    In the end, the rain and Facebook’s lack of ability to send out ‘reminders’ in a robust manner limited somewhat the attendance. Although what was lacking in quantity we made for in quality. Thanks to all who attended and we will see you next time!

    Awesome Flickr Gallery Error - Invalid API Key (Key has invalid format)

  • Metallic c-print photography

    In anticipation of the Maker Sale held at my house, I unearthed some metallic c-print photographs I had taken a few years ago before a family and ‘real’ life came along. The photographs are from interesting locations in and around Toronto, including the Distillery District (I had actually won an award at Pikto for ‘The Conversation’ at that time), the Don Valley Parkway trails, the Brickworks and finally my cottage (not in Toronto this time, but Six Mile Lake).

    Metallic c-print photography is a kind of printing on hyper-glossy photosensitive paper. The paper is so glossy that it has a metallic sheen, thus the name. It is not like printing via an ink-jet printer and is not actually metal. The print, while subject to scratches more than other kinds of photography is archival (100+ years) or so I am told.

    In the case of these photographs, many of them were taken with a medium format Mamiya camera and scanned in via a drum scanner and then stitched together with some additional filtering in Photoshop for maximum effect.

    Does this reappearance of these photographs signal a return to photography? Not likely, but every once in awhile it is interesting to look back and see where I once was.

    Awesome Flickr Gallery Error - Invalid API Key (Key has invalid format)

  • Rethinking 300

    In anticipation of the movie “300 – Rise of an Empire” I recently revisited the original 300 movie. There is little argument that it is one of the most artistic and gory takes of ancient Sparta ever made. It is an underdog story where the Spartans, led by King Leonidas (Gerard Butler) fight against impossible odds against the invading Persians, with only their ability as warriors and (spoiler alert) local geography to help them.

    The first time I saw this film, like most of the audience in the theatre I was thrilled and rooted for the outnumbered Spartans. The movie was aspirational, because you end up identifying with the brave, powerful and chiseled warriors who struggle against the invading hordes. The Persians, while great in number, are often deformed, or somehow freakish in appearance, including their pierced and androgynous leader, Xerxes (Rodrigo Santoro). At first glance, it might seem pretty obvious who are the good guys and who are the bad guys.

    This last viewing of it, however, I changed my mind. This did not come to me slowly after reflecting carefully after having seen it, instead it was more of a thunderclap epiphany during the scene where they all chant in unison. At that moment, the light went on, and I suddenly saw the movie in an entirely different light.

    (From Drew’s Script-O-Rama)

    What is your profession?

    I’m a potter, sir.

    And you, Arcadian.
    What is your profession?

    – Sculptor, sir.
    – Sculptor.

    – And you?
    – Blacksmith.

    Spartans! What is your profession?

    …and it is this point that the Spartans reply in perfect unison and I realized they were a society of perfect conformists.

    For a society to unite against an enemy, it helps to have a common set of goals and values so you can move as one to defend yourself. In the case of the Spartans in this story, these values are (in no particular order) strength, bravery and um…more strength. In the case of these Spartans, their common values are so uniformly ingrained into their society they have become a group of űber conformists. This is the moment of the film where I realized that not only this group of warriors are exactly the same, but their entire culture praises a certain, narrow set of values to the point of atrocity. It has gotten to the point where I knew the villains in the story, and they were not Persian.

    Most obvious of all, this is a group that kills a baby if it does not meet their perfect ideals. And we’re rooting for them? Bizarrely, the flag the Spartans raise in their fight is that of ‘freedom’. Freedom to be what, exactly? The freedom to be just like everyone else or get thrown off a cliff, it seems. And here we are cheering them on as if our eyeballs have some sort of Stockholm Syndrome.

    There is a deliberate irony to the hunchbacked Ephialtes (Andrew Tiernan), who betrays the Spartans after being promised riches and women. He is technically Spartan, but according to their custom should not have even lived. Xerxes takes Ephialtes in, and becomes like a hermaphroditic “wing man” who has your best interests at heart, and accepting of all types, regardless of their difference of appearance.

    It behooves the Spartans to defend their territory against invaders, but think about what values they are defending. You might think that we can’t judge by the standards of today: In a brutal, kill or be kill era, pure strength and toughness are prized qualities. Given that the Spartans appear to ultimately lose, I guess by that yardstick, even they fail their own test of strength at the hands of those who they would not have deemed to have lived more than a few days old.

  • 2013 Maker Faire in Toronto

    Last week I had the pleasure of visiting the 2013 Toronto Mini Maker Faire at Wynchwood Barns. This was a treat for me for a few different reasons, not least of which is this was my first visit to Wynchwood, after following its evolution over the years in the popular press. Of course there was the sheer DIY explosion of creativity at the Faire which I think is the main attraction for nearly everyone who attends.

    My eldest daughter immediately made a beeline for the 3-D printers and my youngest loved the frozen nitrogen ice cream. When asked what they liked after the Faire, they said ‘everything’. Also, there were added bonuses like a cameo by the Leap Motion controller and non-Toronto organizations like think|haus. A nostalgic tear came to my eye watching the robots from R2robotics. Yeah, I’m a geek.

    From the event, I put together a photo blog, where I will be adding comments over the next few days.

    Thanks to the organizers for putting together this great event.