Data is some ficticious student data.
Brush over points to reveal their values in an adjacent table.
forked from sebg's block: Scatter plot + Brush
| license: mit |
Data is some ficticious student data.
Brush over points to reveal their values in an adjacent table.
forked from sebg's block: Scatter plot + Brush
| Name | grade | type | term | number | category | variable1 | variable2 | variable3 | |
|---|---|---|---|---|---|---|---|---|---|
| Ryan Richards | 50 | class | Fall 2015 | 1 | M | 60 | 95 | 60 | |
| Robert Mcdermed | 55 | class | Fall 2015 | 1 | M | 70 | 93 | 70 | |
| Faisal el-Younis | 57 | class | Fall 2015 | 1 | M | 87 | 71 | 90 | |
| Shafeeq el-Saladin | 62 | class | Fall 2015 | 1 | M | 66 | 94 | 70 | |
| Kristopher Santeramo | 65 | class | Fall 2015 | 1 | M | 85 | 71 | 90 | |
| Sergio Cordova | 72 | class | Fall 2015 | 1 | M | 76 | 71 | 80 | |
| Ira Lopez | 78 | class | Fall 2015 | 1 | M | 80 | 86 | 80 | |
| Thanysla Calvert | 80 | class | Fall 2015 | 1 | M | 73 | 84 | 70 | |
| Aliya Mitchell | 85 | class | Fall 2015 | 1 | F | 74 | 92 | 70 | |
| Krystal Wilson | 86 | class | Fall 2015 | 1 | F | 71 | 75 | 70 | |
| Leioka Hyden-Terry | 87 | class | Fall 2015 | 1 | F | 90 | 96 | 90 | |
| Aashtin Crane | 90 | class | Fall 2015 | 1 | F | 78 | 74 | 80 | |
| Lara Ely | 92 | class | Fall 2015 | 1 | F | 85 | 61 | 90 | |
| Lena Lee | 82 | class | Fall 2015 | 1 | F | 74 | 86 | 70 | |
| Isabel Vierra | 83 | class | Fall 2015 | 1 | F | 72 | 69 | 70 | |
| Kimberly Larson | 84 | class | Fall 2015 | 1 | F | 68 | 64 | 70 | |
| Michelle Haynie | 84 | class | Fall 2015 | 1 | F | 90 | 73 | 90 | |
| Gercia Allen | 84 | class | Fall 2015 | 1 | F | 84 | 65 | 80 | |
| Sara Donaldson | 85 | class | Fall 2015 | 1 | F | 74 | 77 | 70 | |
| Ryan Richards | 55 | class | Spring 2016 | 2 | M | 62 | 82 | 60 | |
| Robert Mcdermed | 53 | class | Spring 2016 | 2 | M | 87 | 62 | 90 | |
| Faisal el-Younis | 56 | class | Spring 2016 | 2 | M | 60 | 61 | 60 | |
| Shafeeq el-Saladin | 66 | class | Spring 2016 | 2 | M | 75 | 88 | 80 | |
| Kristopher Santeramo | 70 | class | Spring 2016 | 2 | M | 79 | 67 | 80 | |
| Sergio Cordova | 70 | class | Spring 2016 | 2 | M | 71 | 77 | 70 | |
| Ira Lopez | 81 | class | Spring 2016 | 2 | M | 76 | 66 | 80 | |
| Thanysla Calvert | 82 | class | Spring 2016 | 2 | M | 82 | 74 | 80 | |
| Aliya Mitchell | 83 | class | Spring 2016 | 2 | F | 76 | 75 | 80 | |
| Krystal Wilson | 87 | class | Spring 2016 | 2 | F | 81 | 88 | 80 | |
| Leioka Hyden-Terry | 90 | class | Spring 2016 | 2 | F | 82 | 65 | 80 | |
| Aashtin Crane | 95 | class | Spring 2016 | 2 | F | 74 | 71 | 70 | |
| Lara Ely | 92 | class | Spring 2016 | 2 | F | 87 | 93 | 90 | |
| Lena Lee | 84 | class | Spring 2016 | 2 | F | 86 | 71 | 90 | |
| Isabel Vierra | 85 | class | Spring 2016 | 2 | F | 65 | 67 | 70 | |
| Kimberly Larson | 82 | class | Spring 2016 | 2 | F | 89 | 82 | 90 | |
| Michelle Haynie | 83 | class | Spring 2016 | 2 | F | 86 | 67 | 90 | |
| Gercia Allen | 83 | class | Spring 2016 | 2 | F | 80 | 75 | 80 | |
| Sara Donaldson | 85 | class | Spring 2016 | 2 | F | 90 | 71 | 90 | |
| Ryan Richards | 53 | class | Fall 2016 | 3 | M | 61 | 94 | 60 | |
| Robert Mcdermed | 55 | class | Fall 2016 | 3 | M | 61 | 97 | 60 | |
| Faisal el-Younis | 54 | class | Fall 2016 | 3 | M | 72 | 63 | 70 | |
| Shafeeq el-Saladin | 68 | class | Fall 2016 | 3 | M | 83 | 76 | 80 | |
| Kristopher Santeramo | 67 | class | Fall 2016 | 3 | M | 63 | 75 | 60 | |
| Sergio Cordova | 71 | class | Fall 2016 | 3 | M | 77 | 84 | 80 | |
| Ira Lopez | 78 | class | Fall 2016 | 3 | M | 64 | 79 | 60 | |
| Thanysla Calvert | 81 | class | Fall 2016 | 3 | M | 75 | 77 | 80 | |
| Aliya Mitchell | 87 | class | Fall 2016 | 3 | F | 87 | 95 | 90 | |
| Krystal Wilson | 91 | class | Fall 2016 | 3 | F | 65 | 65 | 70 | |
| Leioka Hyden-Terry | 91 | class | Fall 2016 | 3 | F | 78 | 88 | 80 | |
| Aashtin Crane | 95 | class | Fall 2016 | 3 | F | 63 | 85 | 60 | |
| Lara Ely | 95 | class | Fall 2016 | 3 | F | 73 | 73 | 70 | |
| Lena Lee | 83 | class | Fall 2016 | 3 | F | 80 | 85 | 80 | |
| Isabel Vierra | 88 | class | Fall 2016 | 3 | F | 79 | 74 | 80 | |
| Kimberly Larson | 82 | class | Fall 2016 | 3 | F | 64 | 70 | 60 | |
| Michelle Haynie | 88 | class | Fall 2016 | 3 | F | 84 | 77 | 80 | |
| Gercia Allen | 88 | class | Fall 2016 | 3 | F | 83 | 71 | 80 | |
| Sara Donaldson | 86 | class | Fall 2016 | 3 | F | 68 | 80 | 70 | |
| Ryan Richards | 50 | class | Spring 2017 | 4 | M | 65 | 77 | 70 | |
| Robert Mcdermed | 58 | class | Spring 2017 | 4 | M | 77 | 84 | 80 | |
| Faisal el-Younis | 56 | class | Spring 2017 | 4 | M | 69 | 95 | 70 | |
| Shafeeq el-Saladin | 66 | class | Spring 2017 | 4 | M | 62 | 62 | 60 | |
| Kristopher Santeramo | 72 | class | Spring 2017 | 4 | M | 63 | 85 | 60 | |
| Sergio Cordova | 69 | class | Spring 2017 | 4 | M | 77 | 92 | 80 | |
| Ira Lopez | 77 | class | Spring 2017 | 4 | M | 72 | 66 | 70 | |
| Thanysla Calvert | 85 | class | Spring 2017 | 4 | M | 75 | 88 | 80 | |
| Aliya Mitchell | 88 | class | Spring 2017 | 4 | F | 74 | 90 | 70 | |
| Krystal Wilson | 94 | class | Spring 2017 | 4 | F | 70 | 69 | 70 | |
| Leioka Hyden-Terry | 89 | class | Spring 2017 | 4 | F | 89 | 66 | 90 | |
| Aashtin Crane | 95 | class | Spring 2017 | 4 | F | 61 | 75 | 60 | |
| Lara Ely | 95 | class | Spring 2017 | 4 | F | 82 | 63 | 80 | |
| Lena Lee | 87 | class | Spring 2017 | 4 | F | 77 | 68 | 80 | |
| Isabel Vierra | 88 | class | Spring 2017 | 4 | F | 81 | 95 | 80 | |
| Kimberly Larson | 87 | class | Spring 2017 | 4 | F | 61 | 87 | 60 | |
| Michelle Haynie | 87 | class | Spring 2017 | 4 | F | 76 | 86 | 80 | |
| Gercia Allen | 85 | class | Spring 2017 | 4 | F | 71 | 93 | 70 | |
| Sara Donaldson | 90 | class | Spring 2017 | 4 | F | 78 | 72 | 80 | |
| Ryan Richards | 47 | class | Fall 2017 | 5 | M | 66 | 71 | 70 | |
| Robert Mcdermed | 56 | class | Fall 2017 | 5 | M | 85 | 72 | 90 | |
| Faisal el-Younis | 53 | class | Fall 2017 | 5 | M | 69 | 60 | 70 | |
| Shafeeq el-Saladin | 70 | class | Fall 2017 | 5 | M | 76 | 79 | 80 | |
| Kristopher Santeramo | 77 | class | Fall 2017 | 5 | M | 74 | 87 | 70 | |
| Sergio Cordova | 67 | class | Fall 2017 | 5 | M | 78 | 73 | 80 | |
| Ira Lopez | 76 | class | Fall 2017 | 5 | M | 76 | 63 | 80 | |
| Thanysla Calvert | 83 | class | Fall 2017 | 5 | M | 65 | 88 | 70 | |
| Aliya Mitchell | 87 | class | Fall 2017 | 5 | F | 62 | 60 | 60 | |
| Krystal Wilson | 93 | class | Fall 2017 | 5 | F | 85 | 87 | 90 | |
| Leioka Hyden-Terry | 88 | class | Fall 2017 | 5 | F | 65 | 85 | 70 | |
| Aashtin Crane | 97 | class | Fall 2017 | 5 | F | 79 | 61 | 80 | |
| Lara Ely | 99 | class | Fall 2017 | 5 | F | 75 | 96 | 80 | |
| Lena Lee | 92 | class | Fall 2017 | 5 | F | 74 | 88 | 70 | |
| Isabel Vierra | 93 | class | Fall 2017 | 5 | F | 79 | 73 | 80 | |
| Kimberly Larson | 88 | class | Fall 2017 | 5 | F | 78 | 70 | 80 | |
| Michelle Haynie | 91 | class | Fall 2017 | 5 | F | 76 | 75 | 80 | |
| Gercia Allen | 90 | class | Fall 2017 | 5 | F | 85 | 68 | 90 | |
| Sara Donaldson | 92 | class | Fall 2017 | 5 | F | 66 | 87 | 70 |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| text { | |
| font-family: sans-serif; | |
| fill: #000000; | |
| } | |
| table { | |
| visibility: hidden; | |
| position: absolute; | |
| top: 30px; | |
| left: 500px; | |
| font-family: sans-serif; | |
| font-size: 0.7em; | |
| } | |
| tr:nth-child(even) { | |
| background-color: #d9d9d9; | |
| } | |
| .brushed { | |
| fill: #ff3399; | |
| stroke: #8e1b54; | |
| opacity: 1.0; | |
| } | |
| .non_brushed { | |
| fill: #404040; | |
| opacity: 0.5; | |
| } | |
| </style> | |
| <body> | |
| <!--viz--> | |
| <div id="chart"></div> | |
| <!--table for data of brushed elements--> | |
| <div id="table"> | |
| <table> | |
| <tr> | |
| <th>Name</th> | |
| <th>Grade</th> | |
| <th>Variable1</th> | |
| </tr> | |
| </table> | |
| </div> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <script type="text/javascript"> | |
| // Commented version of | |
| // http://bl.ocks.org/feyderm/6bdbc74236c27a843db633981ad22c1b | |
| // Variables | |
| var margin = {top: 20, right: 0, bottom: 50, left: 85}, | |
| svg_dx = 500, | |
| svg_dy = 400, | |
| plot_dx = svg_dx - margin.right - margin.left, | |
| plot_dy = svg_dy - margin.top - margin.bottom; | |
| // x axis scale | |
| // y axis scale | |
| var x = d3.scaleLinear().range([margin.left, plot_dx]), | |
| y = d3.scaleLinear().range([plot_dy, margin.top]); | |
| // Tick formatting code | |
| //var formatIncome = d3.format(","), | |
| // formatHsGrad = d3.format(""), | |
| // formatHsGradAxis = d3.format(".0%"); | |
| // Create SVG Viewport | |
| var svg = d3.select("#chart") | |
| .append("svg") | |
| .attr("width", svg_dx) | |
| .attr("height", svg_dy); | |
| // CSV AJAX Call | |
| d3.csv("book1.csv", function(d) { | |
| // Figure out number of data elements in the data | |
| var n = d.length; | |
| // Define the extent for the x domain based on numerical income | |
| // Define the extend for the y domain based on hs_grad percentages | |
| var d_extent_x = d3.extent(d, d => +d.variable1), | |
| d_extent_y = d3.extent(d, d => +d.grade); | |
| // Define x and y scale domains based on calculated data | |
| x.domain(d_extent_x); | |
| y.domain(d_extent_y); | |
| // Define x and y axis as well as the respective tick formats | |
| var axis_x = d3.axisBottom(x) | |
| // .tickFormat(formatIncome), | |
| axis_y = d3.axisLeft(y) | |
| // .tickFormat(formatHsGradAxis); | |
| // Draw the X Axis | |
| svg.append("g") | |
| .attr("id", "axis_x") | |
| .attr("transform", "translate(0," + (plot_dy + margin.bottom / 2) + ")") | |
| .call(axis_x); | |
| // Draw the Y Axis | |
| svg.append("g") | |
| .attr("id", "axis_y") | |
| .attr("transform", "translate(" + (margin.left / 2) + ", 0)") | |
| .call(axis_y); | |
| // Label the X Axis | |
| d3.select("#axis_x") | |
| .append("text") | |
| .attr("transform", "translate(360, -10)") | |
| .text("Quiz 1"); | |
| // Label the Y Axis | |
| d3.select("#axis_y") | |
| .append("text") | |
| .attr("transform", "rotate(-90) translate(-20, 15)") | |
| .text("Grades"); | |
| // Create the Scatterplot circles | |
| var circles = svg.append("g") | |
| .selectAll("circle") | |
| .data(d) | |
| .enter() | |
| .append("circle") | |
| .attr("r", 5) | |
| .attr("cx", function(d) { return x(+d.variable1); }) | |
| .attr("cy", function(d) { return y(+d.grade); }) | |
| .attr("class", "non_brushed"); | |
| // Function to run when things are being brushed | |
| // - .on("brush", highlightBrushedCircles) | |
| function highlightBrushedCircles() { | |
| // If something was actually brushed, then do the following | |
| if (d3.event.selection != null) { | |
| // revert circles to initial style | |
| circles.attr("class", "non_brushed"); | |
| // Figure out the brush coordinates | |
| var brush_coords = d3.brushSelection(this); | |
| // style brushed circles | |
| // For each circle in the selection | |
| // - figure out where it is | |
| // - run it through the isBrushed function | |
| // - if the coordinates fall within the brush_coords then keep | |
| // - otherwise, don't do anything | |
| // Finally, for those kept, set class to "brushed" | |
| circles.filter(function () { | |
| // | |
| var cx = d3.select(this).attr("cx"), | |
| cy = d3.select(this).attr("cy"); | |
| return isBrushed(brush_coords, cx, cy); | |
| }) | |
| .attr("class", "brushed"); | |
| } | |
| } | |
| // Function to display the HTML table | |
| // - Function run .on("end", displayTable); | |
| function displayTable() { | |
| // disregard brushes w/o selections | |
| // ref: http://bl.ocks.org/mbostock/6232537 | |
| if (!d3.event.selection) return; | |
| // programmed clearing of brush after mouse-up | |
| // ref: https://github.com/d3/d3-brush/issues/10 | |
| d3.select(this).call(brush.move, null); | |
| var d_brushed = d3.selectAll(".brushed").data(); | |
| // populate table if one or more elements is brushed | |
| if (d_brushed.length > 0) { | |
| clearTableRows(); | |
| d_brushed.forEach(d_row => populateTableRow(d_row)) | |
| } else { | |
| clearTableRows(); | |
| } | |
| } | |
| // Define Brush Behavior | |
| var brush = d3.brush() | |
| .on("brush", highlightBrushedCircles) | |
| .on("end", displayTable); | |
| svg.append("g") | |
| .call(brush); | |
| }); | |
| // Clear the table rows functions | |
| function clearTableRows() { | |
| // First hide the column names | |
| hideTableColNames(); | |
| // Remove all the table rows | |
| d3.selectAll(".row_data").remove(); | |
| } | |
| // Given coordinates of circles and brush_coords | |
| // - get the boundaries from the brush_coords | |
| // - do a massively long boolean comparison | |
| // to make sure circle coordinates are with brush_coords | |
| function isBrushed(brush_coords, cx, cy) { | |
| var x0 = brush_coords[0][0], | |
| x1 = brush_coords[1][0], | |
| y0 = brush_coords[0][1], | |
| y1 = brush_coords[1][1]; | |
| return x0 <= cx && cx <= x1 && y0 <= cy && cy <= y1; | |
| } | |
| // Change HTML Table names to invisible | |
| function hideTableColNames() { | |
| d3.select("table").style("visibility", "hidden"); | |
| } | |
| // Change HTML Table names to visitle | |
| function showTableColNames() { | |
| d3.select("table").style("visibility", "visible"); | |
| } | |
| // Given data for a row, fill it out | |
| function populateTableRow(d_row) { | |
| // Change HTML Table names to visitle | |
| showTableColNames(); | |
| // Create data structure and format as needed | |
| var d_row_filter = [d_row.Name, | |
| formatVariable1(d_row.variable1), | |
| formatGrade(d_row.grade)]; | |
| // Do a data join | |
| // - Add a new row and then do a data join for the <td>'s | |
| // - This way, it'll be only enter selection | |
| // - From data structure above, we'll have three <td>'s | |
| d3.select("table") | |
| .append("tr") | |
| .attr("class", "row_data") | |
| .selectAll("td") | |
| .data(d_row_filter) | |
| .enter() | |
| .append("td") | |
| .attr("align", (d, i) => i == 0 ? "left" : "right") | |
| .text(d => d); | |
| } | |
| </script> | |
| </body> |