{"id":539,"date":"2015-09-23T16:15:16","date_gmt":"2015-09-23T16:15:16","guid":{"rendered":"http:\/\/arlduc.org\/senseandscale\/?p=539"},"modified":"2015-09-28T21:53:54","modified_gmt":"2015-09-28T21:53:54","slug":"bubble-charts","status":"publish","type":"post","link":"https:\/\/arlduc.org\/senseandscale\/?p=539","title":{"rendered":"Data Vis Tutorial: D3 Bubble Chart of NYC Baby Names"},"content":{"rendered":"<p>Full tutorial coming soon! In the meantime, check the JSFiddle below.<\/p>\n\n<!-- iframe plugin v.6.0 wordpress.org\/plugins\/iframe\/ -->\n<iframe loading=\"lazy\" width=\"1000\" height=\"800\" src=\"\/\/jsfiddle.net\/ys97wta9\/embedded\/result\/\" allowfullscreen=\"allowfullscreen\" frameborder=\"0\" scrolling=\"yes\" class=\"iframe-class\"><\/iframe>\n\n<p>This visualization shows the top <a href=\"https:\/\/data.cityofnewyork.us\/Health\/Most-Popular-Baby-Names-by-Sex-and-Mother-s-Ethnic\/25th-nujf\" target=\"_blank\">2011 NYC baby names by mother&#8217;s ethnicity.<\/a><\/p>\n<p>Background from the D3 API reference and more:<\/p>\n<ul>\n<li>bubble chart as\u00a0a flattened <a href=\"https:\/\/github.com\/mbostock\/d3\/wiki\/Pack-Layout\" target=\"_blank\">pack layout<\/a><\/li>\n<li>the pack layout is one of D3&#8217;s <a href=\"https:\/\/github.com\/mbostock\/d3\/wiki\/Hierarchy-Layout\" target=\"_blank\">hierarchy layouts<\/a><\/li>\n<\/ul>\n<p>This tutorial is based on our previous\u00a0<a href=\"http:\/\/arlduc.org\/senseandscale\/?p=498\">bar chart tutorial<\/a>,<a href=\"http:\/\/bl.ocks.org\/mbostock\/4063269\" target=\"_blank\">\u00a0Bostock&#8217;s bubble chart example<\/a>, and InfoCaptor&#8217;s <a href=\"http:\/\/www.infocaptor.com\/bubble-my-page?url=dukode.com&amp;size=800\" target=\"_blank\">Bubble My Page<\/a> service.<\/p>\n<h2>CSS<\/h2>\n<p>We set up a text size and style for our vis.<\/p>\n<pre>text {\r\n font: 10px sans-serif;\r\n}<\/pre>\n<h2>HTML<\/h2>\n<p>We include D3.js for the graphics, and Jquery for the rollovers.<\/p>\n<pre>&lt;script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/d3\/3.5.5\/d3.min.js\"&gt;&lt;\/script&gt;\r\n&lt;script src=\"http:\/\/code.jquery.com\/jquery-latest.min.js\"&gt;&lt;\/script&gt;<\/pre>\n<h2>Javascript<\/h2>\n<p>First we set up the global variables for our visualization size, type, colors, and bubbles.<\/p>\n<pre>var diameter = 700,\r\n format = d3.format(\",d\"),\r\n color = d3.scale.category20c();\r\n\r\nvar bubble = d3.layout.pack()\r\n .sort(null)\r\n .size([diameter, diameter])\r\n .padding(1.5);\r\n\r\nvar svg = d3.select(\"body\").append(\"svg\")\r\n .attr(\"width\", diameter)\r\n .attr(\"height\", diameter)\r\n .attr(\"class\", \"bubble\");<\/pre>\n<p>We then query NYC Open Data for the baby name dataset, and throw an error if this query is not successful.<\/p>\n<pre>d3.csv(\"https:\/\/data.cityofnewyork.us\/resource\/25th-nujf.csv?$limit=10000\", function (error, root) {\r\n if (error) throw error;<\/pre>\n<p>Within the d3.csv function, we set up sub-arrays, divided by ethnicity,\u00a0to record\u00a0baby names and related attributes for each ethnicity type (which are pre-determined in the data set). We also set up arrays called <strong>data<\/strong> and <strong>dobj<\/strong> in which we will concatenate all the sub-arrays.<\/p>\n<pre>\/\/baby names\r\n var AsianNameList=[];\r\n var BlackNameList=[];\r\n var HispanicNameList=[];\r\n var WhiteNameList=[]; \r\n \r\n \/\/number of babies with name\r\n var AsianNameCount=[];\r\n var BlackNameCount=[];\r\n var HispanicNameCount=[];\r\n var WhiteNameCount=[]; \r\n \r\n \/\/ethnicity of mother\r\n var AsianEthnicity=[]; \r\n var BlackEthnicity=[]; \r\n var HispanicEthnicity=[]; \r\n var WhiteEthnicity=[]; \r\n \r\n var data=[]; \/\/3D array of nameList, nameCount, ethnicity\r\n var dobj=[]; \/\/array formated specifically for hierarchical processing<\/pre>\n<p>We now examine all the names in the dataset and bin them into the sub-arrays. There are duplicate records in the dataset, so we only add the name if it&#8217;s not already in the array. We use the &#8220;indexOf&#8221; function to check if the name is already in the array.<\/p>\n<pre>root.forEach(function (d) {\r\n if (+d[\"RNK\"] &lt;= 10) {\r\n \r\n \/\/only add name if it's not uniquely in the array\r\n if ((d[\"ETHCTY\"]===\"ASIAN AND PACIFIC ISLANDER\") &amp;&amp; (AsianNameList.indexOf(d[\"NM\"]) ===-1)) {\r\n AsianNameList.push(d[\"NM\"]);\r\n AsianNameCount.push(+d[\"CNT\"]); \/\/force the string into an integer\r\n AsianEthnicity.push(d[\"ETHCTY\"]);\r\n }\r\n else if ((d[\"ETHCTY\"]===\"BLACK NON HISPANIC\") &amp;&amp; (BlackNameList.indexOf(d[\"NM\"]) ===-1)) {\r\n BlackNameList.push(d[\"NM\"]);\r\n BlackNameCount.push(+d[\"CNT\"]); \/\/force the string into an integer\r\n BlackEthnicity.push(d[\"ETHCTY\"]);\r\n }\r\n else if ((d[\"ETHCTY\"]===\"HISPANIC\") &amp;&amp; (HispanicNameList.indexOf(d[\"NM\"]) ===-1)) {\r\n HispanicNameList.push(d[\"NM\"]);\r\n HispanicNameCount.push(+d[\"CNT\"]); \/\/force the string into an integer\r\n HispanicEthnicity.push(d[\"ETHCTY\"]);\r\n }\r\n else if ((d[\"ETHCTY\"]===\"WHITE NON HISPANIC\") &amp;&amp; (WhiteNameList.indexOf(d[\"NM\"]) ===-1)) {\r\n WhiteNameList.push(d[\"NM\"]);\r\n WhiteNameCount.push(+d[\"CNT\"]); \/\/force the string into an integer\r\n WhiteEthnicity.push(d[\"ETHCTY\"]);\r\n }\r\n }\r\n });<\/pre>\n<p>We then concatenate all this data into one array called <strong>data<\/strong>. There is some simple test data currently commented out; this can be helpful for if you are having trouble managing your larger dataset.<\/p>\n<pre>data=[\r\n \/\/test data is commented out:\r\n \/\/[\"Tea\",\"Coffee\",\"Soda\",\"Chips\",\"Milk\",\"Chocolate\",\"Beer\",\"Wine\"],\r\n \/\/[130,30,200,40,230,150,80,65]\r\n AsianNameList.concat(BlackNameList,WhiteNameList,HispanicNameList), \r\n AsianNameCount.concat(BlackNameCount,WhiteNameCount,HispanicNameCount), \r\n AsianEthnicity.concat(BlackEthnicity,WhiteEthnicity, HispanicEthnicity)\r\n ];<\/pre>\n<p>We prepare an array called\u00a0<strong>dobj<\/strong>\u00a0to record the index\u00a0of each name. We also run the function called\u00a0<strong>display_pack<\/strong>.<\/p>\n<pre>for (var di=0;di&lt;data[0].length;di++) { \r\n   dobj.push({\"key\":di,\"value\":data[1][di]}); \r\n} \r\n\r\ndisplay_pack({children: dobj});<\/pre>\n<p>The function <strong>display_pack<\/strong> consists of three\u00a0parts. First, we\u00a0set up SVG nodes (bubbles):\u00a0here we set up bubble position, color, and mouseover text.<\/p>\n<pre>function display_pack(root) {\r\n var node = svg.selectAll(\".node\")\r\n .data(bubble.nodes(root)\r\n .filter(function(d) { return !d.children; }))\r\n .enter().append(\"g\")\r\n .attr(\"class\", \"node\")\r\n .attr(\"transform\", function(d) { return \"translate(\" + d.x + \",\" + d.y + \")\"; })\r\n .style(\"fill\", function(d) { \r\n \/\/color is based on ethnicity\r\n return color(data[2][d.key]); })\r\n .on(\"mouseover\", function(d) {\r\n d3.select(this).style(\"fill\", \"gold\"); \r\n showToolTip(\" \"+data[0][d.key]+\"&lt;br&gt; \"+data[2][d.key]+\"&lt;br&gt;count: \"+data[1][d.key]+\" \",d.x+d3.mouse(this)[0]+50,d.y+d3.mouse(this)[1],true);\r\n \/\/console.log(d3.mouse(this));\r\n })\r\n \/\/.on(\"mousemove\", function(d,i) {\r\n \/\/tooltipDivID.css({top:d.y+d3.mouse(this)[1],left:d.x+d3.mouse(this)[0]+50});\r\n \/\/}) \r\n .on(\"mouseout\", function() {\r\n d3.select(this).style(\"fill\", function(d) { return color(data[2][d.key]); });\r\n showToolTip(\" \",0,0,false);\r\n });\r\n\r\n<\/pre>\n<p>Then size our bubbles.<\/p>\n<pre>node.append(\"circle\")\r\n .attr(\"r\", function(d) { return d.r; });<\/pre>\n<p>Finally, we add text to our bubbles.<\/p>\n<pre>node.append(\"text\")\r\n .attr(\"dy\", \".3em\")\r\n .style(\"text-anchor\", \"middle\")\r\n .style(\"fill\",\"black\")\r\n .text(function(d) { return data[0][d.key].substring(0, d.r \/ 3); });<\/pre>\n<p style=\"text-align: left;\">The function <strong>showToolTip<\/strong> is called from <strong>display_pack<\/strong>, so we need to write <strong>showToolTip<\/strong>. And that&#8217;s it!<\/p>\n<pre style=\"text-align: left;\">function showToolTip(pMessage,pX,pY,pShow)\r\n {\r\n if (typeof(tooltipDivID)===\"undefined\") {\r\n tooltipDivID =$('&lt;div id=\"messageToolTipDiv\" style=\"position:absolute;display:block;z-index:10000;border:2px solid black;background-color:rgba(0,0,0,0.8);margin:auto;padding:3px 5px 3px 5px;color:white;font-size:12px;font-family:arial;border-radius: 5px;vertical-align: middle;text-align: center;min-width:50px;overflow:auto;\"&gt;&lt;\/div&gt;');\r\n\r\n $('body').append(tooltipDivID);\r\n }\r\n if (!pShow) { tooltipDivID.hide(); return;}\r\n \/\/MT.tooltipDivID.empty().append(pMessage);\r\n tooltipDivID.html(pMessage);\r\n tooltipDivID.css({top:pY,left:pX});\r\n tooltipDivID.show();\r\n }<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Full tutorial coming soon! In the meantime, check the JSFiddle below. This visualization shows the top 2011 NYC baby names by mother&#8217;s ethnicity. Background from the D3 API reference and more: bubble chart as\u00a0a flattened pack layout the pack layout is one of D3&#8217;s hierarchy layouts This tutorial is based on our previous\u00a0bar chart tutorial,\u00a0Bostock&#8217;s [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,8],"tags":[],"class_list":["post-539","post","type-post","status-publish","format-standard","hentry","category-nyu-datavis","category-tutorials"],"_links":{"self":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts\/539","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=539"}],"version-history":[{"count":22,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts\/539\/revisions"}],"predecessor-version":[{"id":584,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=\/wp\/v2\/posts\/539\/revisions\/584"}],"wp:attachment":[{"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=539"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=539"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/arlduc.org\/senseandscale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=539"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}