Saturday, December 13, 2014

Getting your head around d3.js [part2]

Continued from part1.

On observing d3 code, and on observing the output of the program, you'll notice the most confusing parts are that of enter(), data(), datum() and exit(). It just doesn't seem to fit into the programming syntax you're familiar with from other languages. Not to worry, it's just a matter of understanding the purpose of the syntax, and you'll be flying along.

If you wanted to draw a few circles with JavaScript, you'd probably do something like this:
<html>
<body>
<script>
var svgHolder = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svgHolder.setAttribute("height",500);
svgHolder.setAttribute("width",700);
document.body.appendChild(svgHolder);

for(var i = 0; i < 10; i++)
{

var circles = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circles.setAttribute("id", "c"+i)
circles.setAttribute("cx", (i+1)*50)
circles.setAttribute("cy", 100)
circles.setAttribute("r", (i+1)*10)
circles.setAttribute("stroke", "black")
circles.setAttribute("stroke-width", "3")
circles.setAttribute("fill", "red");
svgHolder.appendChild(circles);
}
</script>
</body>
</html>


To do the same thing in d3:

<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var cir = ["c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10"];
var svgHolder = d3.select("body") //select the body tag
                .append("svg") //add an svg tag to body
                    .attr("width", 700) //specify the svg tag properties
                    .attr("height", 500);

svgHolder.selectAll("circle").data(cir).enter()
         .append("circle") //add an svg circle
                .attr("id", function(d) {return d;})
                .attr("cx", function(d,i) {return (i+1)*50;})
                .attr("cy", 110)
                .attr("r", function(d,i) {return (i+1)*10;})
                .attr("stroke", "black")
                .attr("stroke-width", "3")
                .attr("fill", "red");

</script>
</body>
</html>
 


I know what you're thinking:
"Hey, where did the for loop go? What does data() and enter() do? How did you manage to select all circles when none of them were yet created? What is d and i in those functions?"
We are just touching on the tip of the iceberg of the beautifully designed d3 syntax.


SelectAll
The cir array, basically acts as our specification of the loop limit. When you selectAll circle elements in the DOM (if they don't exist yet, d3 will create placeholders for them), you're also feeding each circle with data from the cir array using the data command.

What happens is, that for every circle that is created, d3 will assign the array values from cir to the placeholders one by one. So placeholder 1 will get the value "c1", placeholder 2 gets the value "c2" etc.


Enter and Data
The enter command tells d3 to take whatever commands come after enter, and attach them one by one to the placeholders. So the svg circles that get created with append("circle") will get attached to the placeholders that were created with selectAll("circle"). The number of placeholders to create is determined by the number of array elements in cir.
If you're dealing with only one element, you can use datum() instead of data().

It's that simple.


Anonymous functions and parameters d, i
Now, while specifying attributes for the circle with attr, you'd want to know something about which element of the array you're dealing with, right?
d3 allows you to use anonymous functions which accept zero to three parameters. If you specify the parameter as function(d), the value of d will be the array value of that particular placeholder.
Eg: For the first circle, d will be "c1" , for the second circle, d will be "c2" etc.

The second parameter is i as in function(d, i), which tells you whether the circle is the first one or the second one or third one etc. Similar to the i we use in for loops.

There's also a third parameter that you can get, which gives you data from a parent node, but let's not get into that for now.


Remove
In case you want to remove some of the circles, see how this works:
<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>

var cir = ["c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10"];
var svgHolder = d3.select("body") //select the body tag
                .append("svg") //add an svg tag to body
                    .attr("width", 700) //specify the svg tag properties
                    .attr("height", 500);

svgHolder.selectAll("circle").data(cir).enter()
         .append("circle") //add an svg circle
                .attr("id", function(d) {return d;})
                .attr("cx", function(d,i) {return (i+1)*50;})
                .attr("cy", 110)
                .attr("r", function(d,i) {return (i+1)*10;})
                .attr("stroke", "black")
                .attr("stroke-width", "3")
                .attr("fill", "red");

var removethese = ["c1", "c2", "c3", "c4", "c5", "c9", "c10"];
svgHolder.selectAll("circle").data(removethese).remove();

</script>
</body>
</html> 

 
Interesting, isn't it?
You supply the array that you want to remove using data(), and d3 removes them from the DOM. But there's something wrong with how they got removed. Read on to find out.
btw, you could have also been specific, by typing  svgHolder.selectAll("circle").data(removethese).remove("circle");


Exit
The opposite of enter() though, is exit(). You can use it like this:

<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>

var cir = ["c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10"];
var svgHolder = d3.select("body") //select the body tag
                .append("svg") //add an svg tag to body
                    .attr("width", 700) //specify the svg tag properties
                    .attr("height", 500);

svgHolder.selectAll("circle").data(cir).enter()
         .append("circle") //add an svg circle
                .attr("id", function(d) {return d;})
                .attr("cx", function(d,i) {return (i+1)*50;})
                .attr("cy", 110)
                .attr("r", function(d,i) {return (i+1)*10;})
                .attr("stroke", "black")
                .attr("stroke-width", "3")
                .attr("fill", "red");

var newcir = ["c1", "c2", "c3", "c4", "c5", "c9", "c10"];
svgHolder.selectAll("circle").data(newcir).exit().remove("circle");

</script>
</body>
</html>


Odd, isn't it? All you did is add an exit() between data() and remove(), and it worked exactly as the opposite of remove(). Instead of removing the values you supplied to data(), the values that were not supplied to data() got removed. d3 notices that the new array contains only 7 elements, and retains the first 7 placeholders, and the exit() function tells remove() to remove the remaining 3 placeholders.


A more accurate exit()
Noticed something else? When using just remove(), the first 7 circles got removed. When using it with exit(), the last 3 circles got removed. Both functions were not able to recognize that we had actually removed circles in-between. ie: circles "c6", "c7" and "c8".

To make d3 recognize which array value changed, you just have to supply an extra identity parameter to data().

<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>

var cir = ["c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10"];
var svgHolder = d3.select("body") //select the body tag
                .append("svg") //add an svg tag to body
                    .attr("width", 700) //specify the svg tag properties
                    .attr("height", 500);

svgHolder.selectAll("circle").data(cir, function(d) {return d;}).enter()
         .append("circle") //add an svg circle
                .attr("id", function(d) {return d;})
                .attr("cx", function(d,i) {return (i+1)*50;})
                .attr("cy", 110)
                .attr("r", function(d,i) {return (i+1)*10;})
                .attr("stroke", "black")
                .attr("stroke-width", "3")
                .attr("fill", "red");

var newcir = ["c1", "c2", "c3", "c4", "c5", "c9", "c10"];
svgHolder.selectAll("circle").data(newcir, function(d) {return d;}).exit().remove("circle");

</script>
</body>
</html>


...and viola! enter() and exit() recognize the placeholders by the second parameter we supplied to data().

To conclude
D3.js is a splendid library which allows dynamic creation, removal and modification of DOM elements. It's initially difficult to understand the enter(), exit() and data() syntax, which is why I thought I'd add my own tutorial on the internet to help newbies. Hope this was helpful, and do make use of plenty of anonymous functions and avoid using for loops, because data(), enter() and exit() offer far more powerful ways of dealing with data, than any for loop can. You'll realize it only when you get into more complex ways of representing information on a page, so it's better to start correctly, and use this syntax right from the beginning to make full use of the power of d3.

All the best!



Some people have emailed me asking if they could thank me for having given them knowledge. The best way to thank me is by contributing to Open Source. Being a sweetheart if you'd like to give a more personal thank you, then I don't really like the idea of monetary donations, but  maybe a wishlist wouldn't be that bad.


LOL

Continued from the previous LOL page

Aliens and English
Share with this link




Corporate Hype
Share with this link




Continued in the next LOL page

Monday, December 1, 2014

What a Virtual SIM is

How would you like it if you had to use one computer for accessing your GMail account, another computer for accessing your Facebook account and yet another computer to do your internet banking? Sounds silly, doesn't it? But that's basically what you're doing with your phone.
To use a mobile number, you have a SIM card. To use another number, you have another SIM placed in a separate mobile phone. Dual SIM phones have eased that problem a bit, but what if somebody allowed you to pick up any mobile phone and log-in to the phone with your mobile number, make a call (the billing will be done to your mobile number) and logout of the phone?

Sounds impossible? Futuristic? Well, the future is already here!
In 2008, some brilliant people at Comviva, an Indian company (now owned by Mahindra) and recently, another UK-based company called Movirtu (now acquired by BlackBerry) created the Virtual SIM technology.
What it is

Virtual SIM (I'll be calling it VSIM from now on) is just an imaginary SIM that your mobile phone operator (Airtel, Vodafone, Tata Docomo) will keep in one of their computer databases. Think of it like your Facebook account that's stored on Facebook's database or your GMail account stored in Google's database.
  1. To use a mobile number, you first purchase a Virtual SIM mobile number (which will be owned by an operator like Airtel etc. and you would probably also have the option of getting a real SIM card with it). 
  2. Then either simply borrow somebody's phone (you can use any ordinary phone for this) or use a phone at a phone-booth, enter your VSIM's USSD code (which looks like this: *101# or *139*1*1234567890#) which is how you 'log-in' to your Virtual mobile number. 
  3. The mobile network will identify that the phone is now using a different number, and make a note of it in its VLR (Visitor Location Register) database and it will allow you to make calls using your mobile number and will bill you accordingly. 
  4. Type the same USSD code again, and you'll be logged out.

So basically with VSIM, a mobile phone would have a real SIM in it, and an operator like Airtel would be able to allow even a Vodafone VSIM number to login to the Airtel real SIM, by dynamically assigning the Vodafone number to the real Airtel SIM. This technology even keeps track of your missed calls when you're logged out.
With smart-phones, it wouldn't be difficult to keep multiple virtual numbers logged in at the same time. The implementation is dependent on the phone manufacturers and operators.


Another way of looking at VSIM

Yet another company, Implementa provides Virtual SIM technology in a slightly different way:
Here, the real SIM cards are retained by the mobile phone operator at a SIM storage facility and a SIM emulation adapter is placed in the mobile phone instead of the real SIM card. Using the software interface of the mobile phone, you'll be able to assign one of the real SIM's to the SIM emulation adapter in the phone.


Benefits to mobile operators

Market penetration being crucial for companies, VSIM's have the potential to reach people who do not have the money to afford mobile phones. If one among a community of people has a phone, the others can login to it and use it. Their only expense will be their talk-time.
Another market segment is that of companies which allow BYOD and COPE policies. An employee can use their own number for personal calls and log back into the company number to make official calls. Hopefully this would improve the privacy aspect of smart-phone monitoring too, if the phone gets monitored only when it uses the company VSIM.


I love it when innovative ideas hit the market!