D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
Jamestiberiuseanes
Full window
Github gist
James Eanes - VI8
James Eanes - VI8
<!DOCTYPE html> <html> <meta charset="utf-8"> <!-- Example based on https://bl.ocks.org/weiglemc/6185069 --> <!-- Tooltip example from https://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html --> <style> body { font: 11px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .dot { stroke: #000; } .tooltip { position: absolute; width: 200px; height: 28px; pointer-events: none; } </style> <body> <h1>James Eanes - Visualization Implementation 8 (VI8)</h1> <h4>This first scatterplot shows Rushing Yards and Passing Yards for each player, broken down by conference group, with no restriction on the color choice. In this case, I've allowed D3 to choose from the standard category10 batch of colors for the three groups. It's pretty easy to spot the BigFive and GroupOfFive guys, but the Ind guys blend in (e.g., I had to search for Everett Golson, but finally found his little green dot). </h4> <p> <script src="//d3js.org/d3.v3.min.js"></script> <script src="colorbrewer.js"></script> <script> var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* * value accessor - returns the value to encode for a given data object. * scale - maps value to a visual display encoding, such as a pixel position. * map function - maps from data value to display value * axis - sets up axis */ // setup x var xValue = function(d) { return d["Passing Yards"];}, // data -> value xScale = d3.scale.linear().range([0, width]), // value -> display xMap = function(d) { return xScale(xValue(d));}, // data -> display xAxis = d3.svg.axis().scale(xScale).orient("bottom"); // setup y var yValue = function(d) { return d["Rushing Yards"];}, // data -> value yScale = d3.scale.linear().range([height, 0]), // value -> display yMap = function(d) { return yScale(yValue(d));}, // data -> display yAxis = d3.svg.axis().scale(yScale).orient("left"); // setup fill color var BigFive = {"SEC":"","ACC":"","Big 12":"","Pac-12":"","Big Ten":""}; var GroupOfFive = {"American":"","Sun Belt":"","MWC":"","MAC":"","CUSA":""}; var cValue = function(d) { console.log(d.Conf); if (d.Conf in BigFive) {return "BigFive";} else if (d.Conf in GroupOfFive) {return "GroupOfFive";} else return "Ind";}; color = d3.scale.category10(); // add the graph canvas to the body of the webpage var svg = d3.select("body").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 + ")"); // add the tooltip area to the webpage var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // load data d3.csv("passing-stats-2014.csv", function(error, data) { // change string (from CSV) into number format data.forEach(function(d) { d["Passing Yards"] = +d["Passing Yards"]; d["Rushing Yards"] = +d["Rushing Yards"]; // console.log(d); }); // don't want dots overlapping axis, so add in buffer to data domain xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); // x-axis svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Passing Yards"); // y-axis svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Rushing Yards"); // draw dots svg.selectAll(".dot") .data(data) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", xMap) .attr("cy", yMap) .style("fill", function(d) { return color(cValue(d));}) .on("mouseover", function(d) { tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(d.Player + "<br/>" + d.School + "<br/>" + d.Conf + "<br/> (" + xValue(d) + ", " + yValue(d) + ")") .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); // draw legend var legend = svg.selectAll(".legend") .data(color.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); // draw legend colored rectangles legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color); // draw legend text legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d;}) }); </script> <p> <h4>This next scatterplot shows a colorblind safe version of the same data. It uses ColorBrewer's "3-class Dark2" palette, which is included in the "colorblind safe" set of palettes. However, as we have learned in class, having such a small area (dot) means that it's hard to tell the colors apart from each other. Being partly colorblind myself, I have to look very closely to distinguish close dots of different colors. Also, the outliers (the Ind guys) do not jump out at all to me; but again, that's probably more about the area involved (dot) versus the colors.</h4> <p> <script> var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* * value accessor - returns the value to encode for a given data object. * scale - maps value to a visual display encoding, such as a pixel position. * map function - maps from data value to display value * axis - sets up axis */ // setup x var xValue = function(d) { return d["Passing Yards"];}, // data -> value xScale = d3.scale.linear().range([0, width]), // value -> display xMap = function(d) { return xScale(xValue(d));}, // data -> display xAxis = d3.svg.axis().scale(xScale).orient("bottom"); // setup y var yValue = function(d) { return d["Rushing Yards"];}, // data -> value yScale = d3.scale.linear().range([height, 0]), // value -> display yMap = function(d) { return yScale(yValue(d));}, // data -> display yAxis = d3.svg.axis().scale(yScale).orient("left"); // setup fill color var BigFive = {"SEC":"","ACC":"","Big 12":"","Pac-12":"","Big Ten":""}; var GroupOfFive = {"American":"","Sun Belt":"","MWC":"","MAC":"","CUSA":""}; var cValue2 = function(d) { console.log(d.Conf); if (d.Conf in BigFive) {return "BigFive";}; if (d.Conf in GroupOfFive) {return "GroupOfFive";}; return "Ind";}; color2 = d3.scale.ordinal() .domain(["BigFive","GroupOfFive","Ind"]) .range(colorbrewer.Dark2[3]); // add the graph canvas to the body of the webpage var svg2 = d3.select("body").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 + ")"); // add the tooltip area to the webpage var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // load data d3.csv("passing-stats-2014.csv", function(error, data) { // change string (from CSV) into number format data.forEach(function(d) { d["Passing Yards"] = +d["Passing Yards"]; d["Rushing Yards"] = +d["Rushing Yards"]; // console.log(d); }); // don't want dots overlapping axis, so add in buffer to data domain xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); // x-axis svg2.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Passing Yards"); // y-axis svg2.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Rushing Yards"); // draw dots svg2.selectAll(".dot") .data(data) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", xMap) .attr("cy", yMap) .style("fill", function(d) { return color2(cValue2(d));}) .on("mouseover", function(d) { tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(d.Player + "<br/>" + d.School + "<br/>" + d.Conf + "<br/> (" + xValue(d) + ", " + yValue(d) + ")") .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); // draw legend var legend = svg2.selectAll(".legend") .data(color2.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); // draw legend colored rectangles legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color2); // draw legend text legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d;}) }); </script> <p> <h4>The third scatterplot shows a photocopy safe version of the same data, using the 3- class Set3 palette from ColorBrewer. This palette makes the BigFive and GroupOfFive stand out much better, but the Ind are too close to the BigFive for me to easily identify them (again Everett Golson is right between two BigFive guys, and he blends right into them, at least for me).</h4> <p> <script> var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* * value accessor - returns the value to encode for a given data object. * scale - maps value to a visual display encoding, such as a pixel position. * map function - maps from data value to display value * axis - sets up axis */ // setup x var xValue = function(d) { return d["Passing Yards"];}, // data -> value xScale = d3.scale.linear().range([0, width]), // value -> display xMap = function(d) { return xScale(xValue(d));}, // data -> display xAxis = d3.svg.axis().scale(xScale).orient("bottom"); // setup y var yValue = function(d) { return d["Rushing Yards"];}, // data -> value yScale = d3.scale.linear().range([height, 0]), // value -> display yMap = function(d) { return yScale(yValue(d));}, // data -> display yAxis = d3.svg.axis().scale(yScale).orient("left"); // setup fill color var BigFive = {"SEC":"","ACC":"","Big 12":"","Pac-12":"","Big Ten":""}; var GroupOfFive = {"American":"","Sun Belt":"","MWC":"","MAC":"","CUSA":""}; var cValue2 = function(d) { console.log(d.Conf); if (d.Conf in BigFive) {return "BigFive";}; if (d.Conf in GroupOfFive) {return "GroupOfFive";}; return "Ind";}; color3 = d3.scale.ordinal() .domain(["BigFive","GroupOfFive","Ind"]) .range(colorbrewer.Set3[3]); // add the graph canvas to the body of the webpage var svg3 = d3.select("body").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 + ")"); // add the tooltip area to the webpage var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // load data d3.csv("passing-stats-2014.csv", function(error, data) { // change string (from CSV) into number format data.forEach(function(d) { d["Passing Yards"] = +d["Passing Yards"]; d["Rushing Yards"] = +d["Rushing Yards"]; // console.log(d); }); // don't want dots overlapping axis, so add in buffer to data domain xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); // x-axis svg3.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Passing Yards"); // y-axis svg3.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Rushing Yards"); // draw dots svg3.selectAll(".dot") .data(data) .enter().append("circle") .attr("class", "dot") .attr("r", 3.5) .attr("cx", xMap) .attr("cy", yMap) .style("fill", function(d) { return color3(cValue2(d));}) .on("mouseover", function(d) { tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(d.Player + "<br/>" + d.School + "<br/>" + d.Conf + "<br/> (" + xValue(d) + ", " + yValue(d) + ")") .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); // draw legend var legend = svg3.selectAll(".legend") .data(color3.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); // draw legend colored rectangles legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color3); // draw legend text legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d;}) }); </script> <p> <h4>The fourth scatterplot shows only those QBs in the Big Five, colored by conference, with no restriction on color. In this case, I've allowed D3 to choose from the standard category10 batch of colors for the five conferences. There are colorblind safe options in ColorBrewer for a class of size 5, but there are no photocopy safe options. </h4> <p> <script> var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* * value accessor - returns the value to encode for a given data object. * scale - maps value to a visual display encoding, such as a pixel position. * map function - maps from data value to display value * axis - sets up axis */ // setup x var xValue = function(d) { return d["Passing Yards"];}, // data -> value xScale = d3.scale.linear().range([0, width]), // value -> display xMap = function(d) { return xScale(xValue(d));}, // data -> display xAxis = d3.svg.axis().scale(xScale).orient("bottom"); // setup y var yValue = function(d) { return d["Rushing Yards"];}, // data -> value yScale = d3.scale.linear().range([height, 0]), // value -> display yMap = function(d) { return yScale(yValue(d));}, // data -> display yAxis = d3.svg.axis().scale(yScale).orient("left"); // setup fill color var BigFive = {"SEC":"","ACC":"","Big 12":"","Pac-12":"","Big Ten":""}; var cValue4 = function(d) { console.log(d.Conf); if (d.Conf in BigFive) {return d.Conf;}; }; color4 = d3.scale.ordinal() .domain(["SEC","ACC","Big 12","Pac-12","Big Ten"]) .range(colorbrewer.Accent[5]); // add the graph canvas to the body of the webpage var svg4 = d3.select("body").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 + ")"); // add the tooltip area to the webpage var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // load data d3.csv("passing-stats-2014.csv", function(error, data) { // change string (from CSV) into number format data.forEach(function(d) { d["Passing Yards"] = +d["Passing Yards"]; d["Rushing Yards"] = +d["Rushing Yards"]; // console.log(d); }); // don't want dots overlapping axis, so add in buffer to data domain xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); // x-axis svg4.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Passing Yards"); // y-axis svg4.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Rushing Yards"); // draw dots svg4.selectAll(".dot") .data(data) .enter().append("circle") .filter(function(d) { return d.Conf in BigFive }) .attr("class", "dot") .attr("r", 3.5) .attr("cx", xMap) .attr("cy", yMap) .style("fill", function(d) { return color4(cValue4(d));}) .on("mouseover", function(d) { tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(d.Player + "<br/>" + d.School + "<br/>" + d.Conf + "<br/> (" + xValue(d) + ", " + yValue(d) + ")") .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); // draw legend var legend = svg4.selectAll(".legend") .data(color4.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); // draw legend colored rectangles legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color4); // draw legend text legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d;}) }); </script> <p> <h4>The fifth scatterplot shows only the top 5 QBs, colored by rank, using a multi-hue colormap. I chose ColorBrewer's 5-class BuGn (blue green) color map. It is not easy to tell apart 1-2 and 4-5 from a glance, especially since 1-2 are separated by a considerable amount of white space.</h4> <p> <script> var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* * value accessor - returns the value to encode for a given data object. * scale - maps value to a visual display encoding, such as a pixel position. * map function - maps from data value to display value * axis - sets up axis */ // setup x var xValue = function(d) { return d["Passing Yards"];}, // data -> value xScale = d3.scale.linear().range([0, width]), // value -> display xMap = function(d) { return xScale(xValue(d));}, // data -> display xAxis = d3.svg.axis().scale(xScale).orient("bottom"); // setup y var yValue = function(d) { return d["Rushing Yards"];}, // data -> value yScale = d3.scale.linear().range([height, 0]), // value -> display yMap = function(d) { return yScale(yValue(d));}, // data -> display yAxis = d3.svg.axis().scale(yScale).orient("left"); // setup fill color color5 = d3.scale.ordinal() .range(colorbrewer.BuGn[5]); // add the graph canvas to the body of the webpage var svg5 = d3.select("body").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 + ")"); // add the tooltip area to the webpage var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // load data d3.csv("passing-stats-2014.csv", function(error, data) { // change string (from CSV) into number format data.forEach(function(d) { d["Passing Yards"] = +d["Passing Yards"]; d["Rushing Yards"] = +d["Rushing Yards"]; // console.log(d); }); // don't want dots overlapping axis, so add in buffer to data domain xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); // x-axis svg5.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Passing Yards"); // y-axis svg5.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Rushing Yards"); // draw dots svg5.selectAll(".dot") .data(data) .enter().append("circle") .filter(function(d) { return d.Rk < 6 }) .attr("class", "dot") .attr("r", 3.5) .attr("cx", xMap) .attr("cy", yMap) .style("fill", function(d) { return color5(d.Rk);}) .on("mouseover", function(d) { tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(d.Player + "<br/>" + d.School + "<br/>" + d.Conf + "<br/> (" + xValue(d) + ", " + yValue(d) + ")") .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); // draw legend var legend = svg5.selectAll(".legend") .data(color5.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); // draw legend colored rectangles legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color5); // draw legend text legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d;}) }); </script> <p> <h4>The sixth and finel scatterplot shows only the top 5 QBs, colored by rank, using a single-hue colormap. I chose ColorBrewer's 5-class Blues color map. It is still not easy to tell apart 1-2 and 4-5 from a glance, especially since 1-2 are separated by a considerable amount of white space.</h4> <p> <script> var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; /* * value accessor - returns the value to encode for a given data object. * scale - maps value to a visual display encoding, such as a pixel position. * map function - maps from data value to display value * axis - sets up axis */ // setup x var xValue = function(d) { return d["Passing Yards"];}, // data -> value xScale = d3.scale.linear().range([0, width]), // value -> display xMap = function(d) { return xScale(xValue(d));}, // data -> display xAxis = d3.svg.axis().scale(xScale).orient("bottom"); // setup y var yValue = function(d) { return d["Rushing Yards"];}, // data -> value yScale = d3.scale.linear().range([height, 0]), // value -> display yMap = function(d) { return yScale(yValue(d));}, // data -> display yAxis = d3.svg.axis().scale(yScale).orient("left"); // setup fill color color6 = d3.scale.ordinal() .range(colorbrewer.Blues[5]); // add the graph canvas to the body of the webpage var svg6 = d3.select("body").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 + ")"); // add the tooltip area to the webpage var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); // load data d3.csv("passing-stats-2014.csv", function(error, data) { // change string (from CSV) into number format data.forEach(function(d) { d["Passing Yards"] = +d["Passing Yards"]; d["Rushing Yards"] = +d["Rushing Yards"]; // console.log(d); }); // don't want dots overlapping axis, so add in buffer to data domain xScale.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]); yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); // x-axis svg6.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end") .text("Passing Yards"); // y-axis svg6.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Rushing Yards"); // draw dots svg6.selectAll(".dot") .data(data) .enter().append("circle") .filter(function(d) { return d.Rk < 6 }) .attr("class", "dot") .attr("r", 3.5) .attr("cx", xMap) .attr("cy", yMap) .style("fill", function(d) { return color6(d.Rk);}) .on("mouseover", function(d) { tooltip.transition() .duration(200) .style("opacity", .9); tooltip.html(d.Player + "<br/>" + d.School + "<br/>" + d.Conf + "<br/> (" + xValue(d) + ", " + yValue(d) + ")") .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { tooltip.transition() .duration(500) .style("opacity", 0); }); // draw legend var legend = svg6.selectAll(".legend") .data(color6.domain()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); // draw legend colored rectangles legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color6); // draw legend text legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d;}) }); </script> </body> </html>
https://d3js.org/d3.v3.min.js