Display Data from JSON .on("mouseover", How? - javascript
What I'm trying to do is get a function that when I move my mouse over the Map(USA) that is drawn with a d3.json file that this will show it's data which is stored in a CSV file.
What I'm having trouble with is that I don't know how to implement the mouseover function, because I don't know where I should reference towards.
This is my code. I have no idea how to do this. Any tips would be really appreciated.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Applying a projection to SVG paths</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
//Define map projection
var projection = d3.geo.albersUsa()
.translate([w/2, h/2])
.scale([500]);
//Define path generator
var path = d3.geo.path()
.projection(projection);
//Define quantize scale to sort data values into buckets of color
var color = d3.scale.quantize()
.range(["rgb(237,248,233)","rgb(186,228,179)","rgb(116,196,118)","rgb(49,163,84)","rgb(0,109,44)"]);
//Colors taken from colorbrewer.js, included in the D3 download
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in agriculture data
d3.csv("us-ag-productivity-2004.csv", function(data) {
//Set input domain for color scale
color.domain([
d3.min(data, function(d) { return d.value; }),
d3.max(data, function(d) { return d.value; })
]);
//Load in GeoJSON data
d3.json("us-states.json", function(json) {
//Merge the ag. data and GeoJSON
//Loop through once for each ag. data value
for (var i = 0; i < data.length; i++) {
//Grab state name
var dataState = data[i].state;
//Grab data value, and convert from string to float
var dataValue = parseFloat(data[i].value);
//Find the corresponding state inside the GeoJSON
for (var j = 0; j < json.features.length; j++) {
var jsonState = json.features[j].properties.name;
if (dataState == jsonState) {
//Copy the data value into the JSON
json.features[j].properties.value = dataValue;
//Stop looking through the JSON
break;
}
}
}
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", function(d) {
//Get data value
var value = d.properties.value;
if (value <1.15) {
//If value exists…
return color(value);
} else if (value >1.15) {
return "red"; }
else {
//If value is undefined…
return "#ccc";
}
});
});
});
</script>
</body>
</html>
You must add 3 events mousedown, mousemove, mouseup
const target = document.getElementsByTagName("SVG");
// or by id
const target = document.getElementsById("someid");
target.addEventListener('mousedown', () => {
console.log('mousedown');
});
target.addEventListener('mousemove', () => {
console.log('mousemove');
});
target.addEventListener('mouseup', () => {
console.log('mouseup');
});
but I thing d3.js handle all this, check the official documentation.
Related
Using D3 for painting grid cells multiple times?
I have a tsv file with 100000+ lines and 3 columns: time(ascending, nanoseconds);object;color. In this file each object appears multiple times with different color and time. And i have a grid, where each cell represents one of the objects (about 500+) and their actual color. Here is the Code: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style type="text/css"> svg { width: 90%; height: 400px; } </style> </head> <body> <div id="vis"> <button id="play-button" onclick="runMain()" style="margin-left: 2em; margin-top:2em;">Play </button> <label for="inputDelay">delay:</label> <input type="text" id="inputDelay" placeholder="20" value="20"> </div> <svg></svg> </body> <script src="https://d3js.org/d3.v4.min.js"></script> <script src="https://d3js.org/d3-timer.v1.min.js"></script> <link type="text/css" href="style.css" rel="stylesheet" /> <script type="text/javascript"> let nodeColors2 = ["#33b5e5", "#cc0000", "#669900", "#b4e56b", "#ffbb33", "#f540ff", "#aa18ff", "#16ffa9", "gray"] var playButton = d3.select("#play-button"); createSVG(); function createSVG(numParam) { var svg = d3.select("svg"); var row = svg.selectAll(".row") .data(createGrid(numParam)) .enter().append("g") .attr("class", "row"); var column = row.selectAll(".square") .data(function(d) { return d; }) .enter().append("rect") .attr("class", "square") .attr("id", function(d) { return "rect" + d.id }) .attr("x", function(d) { return d.x; }) .attr("y", function(d) { return d.y; }) .attr("width", function(d) { return d.width; }) .attr("height", function(d) { return d.height; }) .style("fill", "#fff") .style("stroke", "#222"); } /**prescan dataSet for further computation **/ function fileScanning() { return new Promise(function(resolve, reject) { let parameterList = []; setTimeout(() => reject(new Error("setTimeoutError")), 1000); d3.tsv('testFile.tsv', function(data) { data.forEach(function(d) { if (!parameterList.includes(d.param)) { parameterList.push(d.param); } }); resolve(parameterList.sort((a, b) => a - b)); }); }); } /** create grid: cells get a squareID for parameters **/ function createGrid(numParam = 600) { var num_columns = 50; var num_rows = Math.ceil(numParam / num_columns); var data = new Array(); var xpos = 10; //starting xpos and ypos at 10 so the stroke will show when we make the grid below var ypos = 10; var width = 20; var height = 20; var squareID = 0; // iterate for rows for (var row = 0; row < num_rows; row++) { data.push(new Array()); // iterate for cells/columns inside rows for (var column = 0; column < num_columns; column++) { data[row].push({ x: xpos, y: ypos, width: width, height: height, id: "" + squareID }); // each cell gets an ID for further linking to parameters squareID++; // increment the x position. I.e. move it over by 50 (width variable) xpos += width; } // reset the x position after a row is complete xpos = 10; // increment the y position for the next row. Move it down 50 (height variable) ypos += height; } return data; } async function runMain() { let delay = document.getElementById('inputDelay').value; d3.select("svg").selectAll(".row").remove(); let parameterList = await fileScanning(); createSVG(parameterList.length); /** run through dataSet and change nodecolors line for line**/ d3.tsv('testFile.tsv', function(data) { for (let i = 0; i < data.length; i++) { setTimeout(() => { document.querySelector("#rect" + parameterList.indexOf(data[i].param)).setAttribute("style", "fill:" + nodeColors2[data[i].target] + "; stroke: black;"); }, i * delay); } }); } </script> </html> The dataset looks like this where object=param and color=target: time param target 5396736 0 0 21620736 307000 5 36134400 430000 7 38073600 369000 6 39064064 246000 4 39318784 123000 2 48853504 62000 1 58494720 1000 0 65408512 185000 3 87599616 431000 7 87736832 247000 4 90412544 308000 5 91149568 370000 6 96732416 63000 1 96962816 124000 2 116216064 2000 0 117147392 186000 3 i want to start the visualisation (like youtube: variable speed, slider, possible to play/pause, back and forth) and while time is running it should always check the time in the file if an object needs to be updated. so, e.g. beeing at 45 seconds and all objects should represent their latest color update until that time. As a newbie in general but especially in D3 i am wondering if D3 is a good choice and if so how my approach should look like or if i shouldn't use D3 with these requirements at all? I didn't figure out to fully understand update,enter and exit, yet but it feels like it should be the answer. If so i have no clue how the approach for "rewinding" should look like, since it shouldn't delete an object but repaint it with its latest color before the chosen time. Here is the latest working example on plunker with a very small dataset for better understanding. It is supposed to look like this (missing the whole slider functionality like in youtube). But it is not supposed to use setTimeout for the moments of painting. I want to use "real time" from the tsv file. As best fit got these sources: slider, grid. With slider i am having trouble to change the Date approach into my nanoseconds. Do you have some help if D3 will work and how to approach all of this since i am a bit lost? PS: First question for me: Any suggestion for a better title of this question? I am happy to edit my question to make it more comfortable for everyone.
D3.js Problem rendering barchart with object data
I have the following script for rendering a simple barchart in D3.js. I have been able to render charts ok up until a point. I have this data below which I am struggling to insert into my chart, there is no specific key I can call upon and I'm really confused how I would insert all of these into my chart. Object { "food-environmental-science": 0, "art-media-research": 0, .....} I have a seperate file for the HTML (only a snippet): var barchart1 = barchart("#otherchart"); function clickScatter(d){ var unitOfAssessment = d.UoAString; click = d.environment.topicWeights renderTopicWeights(click) } function renderTopicWeights(clickedPoint){ barchart1.loadAndRenderDataset(clickedPoint) } When I call upon the loadAndRenderDataset function, console gives me a data.map is not a function error. function barchart(targetDOMelement) { //=================== PUBLIC FUNCTIONS ========================= // barchartObject.appendedMouseOverFunction = function (callbackFunction) { console.log("appendedMouseOverFunction called", callbackFunction) appendedMouseOverFunction = callbackFunction; render(); return barchartObject; } barchartObject.appendedMouseOutFunction = function (callbackFunction) { appendedMouseOutFunction = callbackFunction; render(); return barchartObject; } barchartObject.loadAndRenderDataset = function (data) { dataset=data.map(d=>d); //create local copy of references so that we can sort etc. render(); return barchartObject; } barchartObject.overrideDataFieldFunction = function (dataFieldFunction) { dataField = dataFieldFunction; return barchartObject; } barchartObject.overrideKeyFunction = function (keyFunction) { //The key function is used to obtain keys for GUP rendering and //to provide the categories for the y-axis //These valuse should be unique GUPkeyField = yAxisCategoryFunction = keyFunction; return barchartObject; } barchartObject.overrideMouseOverFunction = function (callbackFunction) { mouseOverFunction = callbackFunction; render(); return barchartObject; } barchartObject.overrideMouseOutFunction = function (callbackFunction) { mouseOutFunction = callbackFunction; render(); //Needed to update DOM return barchartObject; } barchartObject.overrideTooltipFunction = function (toolTipFunction) { tooltip = toolTipFunction; return barchartObject; } barchartObject.overrideMouseClickFunction = function (fn) { mouseClick2Function = fn; render(); //Needed to update DOM if they exist return barchartObject; } barchartObject.render = function (callbackFunction) { render(); //Needed to update DOM return barchartObject; } barchartObject.setTransform = function (t) { //Set the transform on the svg svg.attr("transform", t) return barchartObject; } barchartObject.yAxisIndent = function (indent) { yAxisIndent=indent; return barchartObject; } //=================== PRIVATE VARIABLES ==================================== //Width and height of svg canvas var svgWidth = 900; var svgHeight = 450; var dataset = []; var xScale = d3.scaleLinear(); var yScale = d3.scaleBand(); //This is an ordinal (categorical) scale var yAxisIndent = 400; //Space for labels var maxValueOfDataset; //For manual setting of bar length scaling (only used if .maxValueOfDataset() public method called) //=================== INITIALISATION CODE ==================================== //Declare and append SVG element var svg = d3 .select(targetDOMelement) .append("svg") .attr("width", svgWidth) .attr("height", svgHeight) .classed("barchart",true); //Declare and add group for y axis var yAxis = svg .append("g") .classed("yAxis", true); //Declare and add group for x axis var xAxis = svg .append("g") .classed("xAxis", true); //===================== ACCESSOR FUNCTIONS ========================================= var dataField = function(d){return d.datafield} //The length of the bars var tooltip = function(d){return d.key + ": "+ d.datafield} //tooltip text for bars var yAxisCategoryFunction = function(d){return d.key} //Categories for y-axis var GUPkeyField = yAxisCategoryFunction; //For 'keyed' GUP rendering (set to y-axis category) //=================== OTHER PRIVATE FUNCTIONS ==================================== var maxValueOfDataField = function(){ //Find the maximum value of the data field for the x scaling function using a handy d3 max() method //This will be used to set (normally used ) return d3.max(dataset, dataField) }; var appendedMouseOutFunction = function(){}; var appendedMouseOverFunction = function(){}; var mouseOverFunction = function (d,i){ d3.select(this).classed("highlight", true).classed("noHighlight", false); appendedMouseOverFunction(d,i); } var mouseOutFunction = function (d,i){ d3.select(this).classed("highlight", false).classed("noHighlight", true); appendedMouseOutFunction(d,i); } var mouseClick2Function = function (d,i){ console.log("barchart click function = nothing at the moment, d=",d) }; function render () { updateScalesAndRenderAxes(); GUP_bars(); } function updateScalesAndRenderAxes(){ //Set scales to reflect any change in svgWidth, svgHeight or the dataset size or max value xScale .domain([0, maxValueOfDataField()]) .range([0, svgWidth-(yAxisIndent+10)]); yScale .domain(dataset.map(yAxisCategoryFunction)) //Load y-axis categories into yScale .rangeRound([25, svgHeight-40]) .padding([.1]); //Now render the y-axis using the new yScale var yAxisGenerator = d3.axisLeft(yScale); svg.select(".yAxis") .transition().duration(1000).delay(1000) .attr("transform", "translate(" + yAxisIndent + ",0)") .call(yAxisGenerator); //Now render the x-axis using the new xScale var xAxisGenerator = d3.axisTop(xScale); svg.select(".xAxis") .transition().duration(1000).delay(1000) .attr("transform", "translate(" + yAxisIndent + ",20)") .call(xAxisGenerator); }; function GUP_bars(){ //GUP = General Update Pattern to render bars //GUP: BIND DATA to DOM placeholders var selection = svg .selectAll(".bars") .data(dataset, GUPkeyField); //GUP: ENTER SELECTION var enterSel = selection //Create DOM rectangles, positioned # x=yAxisIndent .enter() .append("rect") .attr("x", yAxisIndent) enterSel //Add CSS classes .attr("class", d=>("key--"+GUPkeyField(d))) .classed("bars enterSelection", true) .classed("highlight", d=>d.highlight) enterSel //Size the bars .transition() .duration(1000) .delay(2000) .attr("width", function(d) {return xScale(dataField(d));}) .attr("y", function(d, i) {return yScale(yAxisCategoryFunction(d));}) .attr("height", function(){return yScale.bandwidth()}); enterSel //Add tooltip .append("title") .text(tooltip) //GUP UPDATE (anything that is already on the page) var updateSel = selection //update CSS classes .classed("noHighlight updateSelection", true) .classed("highlight enterSelection exitSelection", false) .classed("highlight", d=>d.highlight) updateSel //update bars .transition() .duration(1000) .delay(1000) .attr("width", function(d) {return xScale(dataField(d));}) .attr("y", function(d, i) {return yScale(yAxisCategoryFunction(d));}) .attr("height", function(){return yScale.bandwidth()}); updateSel //update tool tip .select("title") //Note that we already created a <title></title> in the Enter selection .text(tooltip) //GUP: Merged Enter & Update selections (so we don't write these twice) var mergedSel = enterSel.merge(selection) .on("mouseover", mouseOverFunction) .on("mouseout", mouseOutFunction) .on("click", mouseClick2Function) //GUP EXIT selection var exitSel = selection.exit() .classed("highlight updateSelection enterSelection", false) .classed("exitSelection", true) .transition() .duration(1000) .attr("width",0) .remove() }; return barchartObject;' } Any help would be much appreciated, and I appolguise if what I'm asking is not clear. Thanks
format your input data into object like {key:"",value:""} and pass this into d3 so that they can understand and render chart. var input = {'a':1,"b":2}; function parseData(input){ return Object.keys(input).reduce(function(output, key){ output.push({"key":key,"value":input[key]}); return output; },[]) } console.log(parseData(input)); // [{"key":"a","value":1},{"key":"b","value":2}] jsFiddle demo - https://jsfiddle.net/1kdsoyg2/1/
d3js v5 + Topojson v3 Show/Hide element on click legend
I would like this reverse action http://bl.ocks.org/d3noob/5d621a60e2d1d02086bf. When I click on an item of my legend, I want focus all elements of the map within these class. However, how isolate just one class compared to others? For example in this image, just show elements where the value is included between 23500 and 29000 and hide other elements. I suggest to 1/ filter data and 2/ fill with the same color these elements but surely it's easier. Here is my code : https://plnkr.co/edit/ga82Syjc8zxTdAxTVNXu?p=preview <!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://unpkg.com/d3#5.0.0/dist/d3.min.js"></script> <script src="https://unpkg.com/topojson#3.0.0/dist/topojson.min.js"></script> </head> <svg class="carte_evolution"> <style> </style> <body> <script> let w = 600; let h = 600; let view = [0,0,600,600]; //Dimension let svgCarteEvolution = d3.select(".carte_evolution") .attr("width", "100%") .attr("height", h) .attr("preserveAspectRatio","xMidYMid meet") .attr("viewBox", `${view[0]},${view[1]},${view[2]},${view[3]}`); //Map projection choro = d3.map(); projection = d3.geoConicConformal() .center([1.282743, 46.328377]) .scale(2600) .translate([w / 2, h / 2]); path = d3.geoPath() .projection(projection); //Load csv and topojson promises1 = d3.json("ze_WGS84_UTF8.topojson"); promises2 = d3.csv("data.csv"); Promise.all([promises1, promises2]).then(function(fr){ //Join csv + topojson let featureCollection = topojson.feature(fr[0],fr[0].objects.ze_WGS84_UTF8) for (var i=0; i< fr[1].length;i++){ var csvId = fr[1][i].codgeo; var csvValue0 = parseFloat(fr[1][i].value0); var csvYear0 = fr[1][i].year0; for (var j=0; j<featureCollection.features.length;j++){ var jsonId = featureCollection.features[j].properties.codgeo; if (csvId === jsonId) { featureCollection.features[j].properties.value0 = csvValue0; featureCollection.features[j].properties.year0 = csvYear0; break; } } } let color = d3.scaleQuantile() .range(["#d1e0c9","#b3cea8","#8fb983","#539f53","#008d36"]); color.domain([ 12000,17500,19500,21500,23500,29000 ]); //Map svgCarteEvolution.append("g") .selectAll("path") .data(featureCollection.features) .enter() .append("path") .attr("class", "dep") .attr("d", path) .style("fill", function(d){ var value = d.properties["value0"]; return value? color(value):"#ccc"; }); //legend let legend = svgCarteEvolution.selectAll("g.legend_entree") .data(color.range().reverse()) .enter() .append("g") .attr("class","legend_entree"); legend .append('rect') .attr("x", 30) .attr("y", function(d, i) { return 65 + i * 20; }) .attr("width", 20) .attr("height", 10) .style("stroke", "black") .style("stroke-width", 0.1) .style("fill", function(d){return d;}); //the data objects are the fill colors legend .append('text') .attr("x", 55) //leave 5 pixel space after the <rect> .attr("y", function(d, i) { return 65 + i * 20; }) .attr("dy", "0.8em") //place text one line *below* the x,y point .style("font-family","latomedium") .style("font-size","0.9em") .text(function(d,i) { var extent = color.invertExtent(d); //extent will be a two-element array, format it however you want: var format = d3.format(""); return `${format(+extent[0])} - ${format(+extent[1])}` }); }); </script> </body> </html> data.csv "codgeo","year0","value0","year1","value1" "0050",2012,19162,2014,19698.8 "0051",2012,18501.125,2014,19125.5 "0052",2012,18684.6666666667,2014,19454 "0053",2012,19826,2014,20573.9 "0054",2012,18881.1111111111,2014,19513 "0055",2012,17942.5,2014,18657.3 "0056",2012,19299.0476190476,2014,19703.9 "0057",2012,18873.8095238095,2014,19539.3 "0059",2012,18199,2014,18719 "0060",2012,18921,2014,19563.2 "0061",2012,21259.5238095238,2014,21748.3 "0101",2012,,2014, "0102",2012,,2014, "0103",2012,,2014, "0106",2012,,2014, "0201",2012,,2014,17250 "0202",2012,,2014,17246.7 "0203",2012,,2014,14972 "0204",2012,,2014,14612.6 "0205",2012,,2014,15617.3 "0206",2012,,2014,13369 "0301",2012,,2014, "0302",2012,,2014, "0303",2012,,2014, "0401",2012,,2014,12522.3 "0402",2012,,2014,15483.8 "0403",2012,,2014,14344.6 "0404",2012,,2014,13134 "0601",2012,,2014, "1101",2012,23144.7619047619,2014,23464 "1102",2012,22223.5,2014,22729.1 "1103",2012,20637.2222222222,2014,21088 "1104",2012,20402,2014,20901 "1105",2012,21782.7777777778,2014,22274.4 "1106",2012,18304.375,2014,18918 "1107",2012,20038.6666666667,2014,20406.5 "1108",2012,19493,2014,19936.5 "1109",2012,28156.8901098901,2014,28660 "1110",2012,20294.8,2014,20639.5 "1111",2012,22490.6666666667,2014,22812.4 "1112",2012,25996.6666666667,2014,26503.5 "1113",2012,25301.7391304348,2014,25639.6 "1114",2012,21184,2014,21611.9 "1115",2012,20586,2014,20954 "1116",2012,25449.5,2014,25742.4 "1117",2012,22279.3333333333,2014,22665 "1118",2012,19040,2014,19307.2 "1119",2012,22059.0909090909,2014,22519 "2101",2012,17416,2014,18133.9 "2102",2012,18721,2014,19275.4 "2103",2012,19554.7826086957,2014,20204 "2104",2012,20352.8571428571,2014,20892.8 "2105",2012,19630.5555555556,2014,20157.6 "2106",2012,18689,2014,19445.2 "2107",2012,17676.6666666667,2014,18309.1 "2201",2012,19209.5238095238,2014,19791 "2202",2012,17090,2014,17820 "2203",2012,16258.6666666667,2014,17014 "2204",2012,17987.619047619,2014,18675.2 "2205",2012,17320.8333333333,2014,18056 "2206",2012,18163.2,2014,18851 "2207",2012,19732.1428571429,2014,20284.7 "2208",2012,19973.3333333333,2014,20690 "2209",2012,17625,2014,18402 "2210",2012,18778.0952380952,2014,19447.6 "2211",2012,17420,2014,18158.8 "2301",2012,18978.8461538462,2014,19609.3 "2302",2012,19920,2014,20419 "2303",2012,18947,2014,19704.7 "2304",2012,20011.7391304348,2014,20639 "2305",2012,18633.4166666667,2014,19348.6 "2306",2012,19222.6666666667,2014,19937.6 "2307",2012,19716,2014,20349.3 "2401",2012,19496,2014,20116.7 "2402",2012,17587.3913043478,2014,18264.3 "2403",2012,18039.3333333333,2014,18668.9 "2404",2012,20862,2014,21386.8 "2405",2012,19088,2014,19617.5 "2406",2012,19682,2014,20246 "2407",2012,17765,2014,18244 "2408",2012,18813.3333333333,2014,19590.5 "2409",2012,18460.8695652174,2014,19134 "2410",2012,19341.3333333333,2014,20286.2 "2411",2012,18503.5,2014,19170 "2412",2012,20074.7619047619,2014,20669 "2413",2012,19886,2014,20426.5 "2414",2012,18549,2014,19111.7 "2415",2012,19298.0952380952,2014,19929 "2416",2012,19159.5833333333,2014,19763.3 "2417",2012,19013.3333333333,2014,19521.9 "2418",2012,20852,2014,21314 "2419",2012,19696.8,2014,20135.4 "2501",2012,18832.9166666667,2014,19616.7 "2502",2012,19839.6428571429,2014,20447.3 "2503",2012,19357,2014,19949.3 "2504",2012,17890,2014,18668.5 "2505",2012,17836.1904761905,2014,18619.5 "2506",2012,18373.0434782609,2014,19247.3 "2507",2012,18855,2014,19788.7 "2508",2012,18192.0833333333,2014,19076 "2509",2012,19105,2014,19896.6 "2510",2012,18837.2222222222,2014,19621.4 "2511",2012,18071.5,2014,18835 "2512",2012,18059.5,2014,18796.7 "2513",2012,17989.5652173913,2014,18533.5 "2601",2012,20356,2014,21106.7 "2602",2012,18218.4,2014,18926.7 "2603",2012,20719.6666666667,2014,21264.4 "2604",2012,18828.3333333333,2014,19445.7 "2605",2012,17496,2014,18232 "2606",2012,18618.3333333333,2014,19419.2 "2607",2012,18150,2014,18717 "2608",2012,19290,2014,20024 "2609",2012,18376,2014,19020 "2610",2012,18123.5,2014,18997.2 "2611",2012,18232,2014,19093.1 "2612",2012,19023.3962264151,2014,19581.7 "2613",2012,18402.2222222222,2014,19055 "2614",2012,19352.6666666667,2014,19970 "3110",2012,17632,2014,18171.3 "3111",2012,19872.3214285714,2014,20498.6 "3112",2012,17909.5,2014,18786 "3113",2012,19370.8695652174,2014,20029 "3114",2012,17411.6666666667,2014,18153.1 "3115",2012,16527.5,2014,17161.7 "3116",2012,17494,2014,18124.5 "3117",2012,16522.5,2014,17252.5 "3121",2012,18958.5714285714,2014,19749.5 "3122",2012,15848,2014,16471.3 "3123",2012,17325,2014,18070 "3124",2012,17319,2014,18080.7 "3125",2012,16943,2014,17776.5 "3126",2012,17054,2014,17783.8 "3127",2012,17860.6666666667,2014,18527.8 "4101",2012,19057,2014,20396.5 "4102",2012,18167.3913043478,2014,18923.8 "4103",2012,20100,2014,20734.3 "4104",2012,19253.4615384615,2014,19914.7 "4105",2012,18178,2014,18899.6 "4106",2012,18415.5555555556,2014,19180 "4107",2012,19765.3333333333,2014,20611.4 "4108",2012,17936.3043478261,2014,18670.5 "4109",2012,19220,2014,19884 "4110",2012,19699,2014,20456 "4111",2012,19975.5555555556,2014,21490 "4112",2012,18561.9047619048,2014,19239.6 "4113",2012,18533,2014,19207 "4114",2012,17932,2014,18625 "4115",2012,18513.6,2014,19304 "4201",2012,21662,2014,22259.4 "4202",2012,22121.4285714286,2014,22678 "4203",2012,20694.9743589744,2014,21249.2 "4204",2012,20996.6666666667,2014,21554 "4205",2012,20637.2,2014,20939.5 "4206",2012,22284.4,2014,22998 "4207",2012,21402,2014,21892 "4208",2012,20530.4761904762,2014,20987.7 "4209",2012,27116,2014,27578 "4301",2012,19866.7857142857,2014,20474.7 "4302",2012,19037.6923076923,2014,19688.7 "4303",2012,26342.380952381,2014,26900.4 "4304",2012,23223.3333333333,2014,24219 "4305",2012,19166.4516129032,2014,19840 "4306",2012,19092.2222222222,2014,19879.5 "4307",2012,20652,2014,21500.8 "4308",2012,18128,2014,18743 "4309",2012,18185,2014,18844.7 "5201",2012,18881.4814814815,2014,19667.6 "5202",2012,17665.6,2014,18286 "5203",2012,20616,2014,21241 "5204",2012,19844.8,2014,20508 "5205",2012,19443,2014,20094.4 "5206",2012,18905.7142857143,2014,19605 "5207",2012,17964.6666666667,2014,18666 "5208",2012,18107.3333333333,2014,18734.4 "5209",2012,18951.7857142857,2014,19703.8 "5210",2012,18635.7142857143,2014,19332 "5211",2012,18973.2258064516,2014,19556.5 "5212",2012,18178.6666666667,2014,18824 "5213",2012,19304.6666666667,2014,19966.7 "5214",2012,18363.3333333333,2014,19098.9 "5215",2012,19146.6666666667,2014,19786.7 "5216",2012,18103.3333333333,2014,18876.7 "5217",2012,18984,2014,19686 "5218",2012,19186.1904761905,2014,19813.8 "5219",2012,20042.380952381,2014,20712.9 "5301",2012,19939.2,2014,20655.3 "5302",2012,18221.4285714286,2014,18960 "5303",2012,20016,2014,20691.3 "5304",2012,18641.5,2014,19282.2 "5305",2012,19581.3333333333,2014,20232.9 "5306",2012,19916.0869565217,2014,20649.4 "5307",2012,17941.3333333333,2014,18671 "5308",2012,19373.3333333333,2014,19991.9 "5309",2012,19634.347826087,2014,20377.6 "5310",2012,18645.3846153846,2014,19283.8 "5311",2012,18720,2014,19397.2 "5312",2012,20578,2014,21143.8 "5313",2012,19380.6666666667,2014,20159.3 "5314",2012,19439,2014,20248.1 "5315",2012,19573,2014,20304.3 "5316",2012,18751.25,2014,19417.2 "5317",2012,18940,2014,19701.3 "5318",2012,20075.4166666667,2014,20740 "5401",2012,17907.5,2014,18522.9 "5402",2012,18704.6666666667,2014,19349 "5403",2012,18580.3846153846,2014,19280 "5404",2012,17407,2014,18222 "5405",2012,19327.5,2014,20055.3 "5406",2012,18512.4,2014,19128 "5407",2012,19217.6,2014,19903.5 "5408",2012,18673,2014,19379.3 "5409",2012,20270,2014,20855.6 "5410",2012,19489.1666666667,2014,20238.1 "5411",2012,17890,2014,18620.5 "5412",2012,18078.0952380952,2014,18834 "5413",2012,19446.5,2014,20043 "7201",2012,18008.4637681159,2014,18697.3 "7202",2012,18425,2014,19159 "7203",2012,18106.6666666667,2014,18658.7 "7204",2012,20667,2014,21249.5 "7205",2012,18035.3333333333,2014,18711.3 "7206",2012,18450.9523809524,2014,19101.3 "7207",2012,20320.8695652174,2014,20948 "7208",2012,19536,2014,20100 "7209",2012,18869.3333333333,2014,19480.7 "7210",2012,17737.5,2014,18362 "7211",2012,17410,2014,17987.6 "7212",2012,20164.6666666667,2014,20683.9 "7213",2012,19245,2014,19834 "7214",2012,20302,2014,20867.6 "7301",2012,18256,2014,18876.3 "7302",2012,17957,2014,18514 "7303",2012,18034.6666666667,2014,18724.8 "7304",2012,19017.2222222222,2014,19799.3 "7305",2012,17916.1904761905,2014,18698 "7306",2012,18578,2014,19336.7 "7307",2012,18857.619047619,2014,19230 "7308",2012,18793.3333333333,2014,19457.6 "7309",2012,19058.6956521739,2014,19787.6 "7310",2012,18895.3333333333,2014,19429.5 "7311",2012,18878.1780538302,2014,19430.7 "7312",2012,18183.8461538462,2014,18879.2 "7313",2012,18197.3333333333,2014,18632 "7401",2012,19040,2014,19716 "7402",2012,18143.3333333333,2014,18897.2 "7403",2012,17301.3043478261,2014,17984 "7404",2012,19118,2014,19698 "8201",2012,20643.8095238095,2014,21227.1 "8202",2012,20174.6666666667,2014,20682.4 "8203",2012,18474.4444444444,2014,19119.6 "8204",2012,18964.6153846154,2014,19694 "8205",2012,17833.8461538462,2014,18486 "8206",2012,18796,2014,19433 "8207",2012,18750.4347826087,2014,19414.5 "8208",2012,19158.8,2014,19833.1 "8209",2012,20058.9655172414,2014,20741.1 "8210",2012,21119.1153846154,2014,21684.5 "8211",2012,19926,2014,20499.3 "8212",2012,18585.7142857143,2014,19272 "8213",2012,21155,2014,21768 "8214",2012,20965,2014,21470 "8215",2012,20356.9230769231,2014,20849.2 "8216",2012,21009.6,2014,21576.5 "8217",2012,20380.7692307692,2014,20996 "8218",2012,23005.2173913043,2014,23712.7 "8219",2012,27201.9230769231,2014,27749.3 "8220",2012,21017,2014,21626.5 "8221",2012,21245.0909090909,2014,21706.7 "8222",2012,23036.0869565217,2014,23862.9 "8301",2012,18453.9393939394,2014,19023.3 "8302",2012,18534.3333333333,2014,19190 "8303",2012,18492,2014,19091.3 "8304",2012,18855.7142857143,2014,19606.7 "8305",2012,17307.5595238095,2014,18159 "8306",2012,17459.1666666667,2014,18457 "8307",2012,17890.4761904762,2014,18484.8 "8308",2012,18963,2014,19466.1 "8309",2012,18347.1428571429,2014,19084 "8310",2012,20412,2014,21071.7 "8311",2012,19008.5,2014,19795.7 "8312",2012,18111.6666666667,2014,18856.5 "9101",2012,17408.5714285714,2014,17945.3 "9102",2012,16617.3333333333,2014,17173 "9103",2012,17123.3333333333,2014,17661 "9104",2012,16840,2014,17349.6 "9105",2012,18586,2014,19386.7 "9106",2012,18106.6666666667,2014,18625 "9107",2012,17128.4615384615,2014,17763 "9108",2012,16940.8695652174,2014,17503.5 "9109",2012,17352,2014,17867.5 "9110",2012,16858,2014,17391.3 "9111",2012,19566.6666666667,2014,20024.4 "9112",2012,17690.4,2014,18320.7 "9113",2012,18336.5217391304,2014,19110 "9114",2012,18100.4545454545,2014,18640.7 "9115",2012,17447.2222222222,2014,17903.9 "9116",2012,17108,2014,17654.6 "9301",2012,18502,2014,19034.2 "9302",2012,18934.8,2014,19401.5 "9303",2012,18952.3076923077,2014,19365.3 "9304",2012,18794.7619047619,2014,19335 "9305",2012,20466.1111111111,2014,20830.8 "9306",2012,20292.8,2014,20668.7 "9307",2012,19959,2014,20333.3 "9308",2012,21603.3333333333,2014,22211.1 "9309",2012,18084,2014,18679.5 "9310",2012,19009,2014,19507 "9311",2012,19514.6666666667,2014,20090 "9312",2012,19813.6,2014,20490.6 "9313",2012,18840,2014,19254.8 "9314",2012,19946.0357142857,2014,20238 "9315",2012,19492,2014,20070.5 "9316",2012,17739.1304347826,2014,18245.7 "9317",2012,17904,2014,18510.6 "9401",2012,19633.8461538462,2014,20418.3 "9402",2012,17570,2014,17890 "9403",2012,17200.8333333333,2014,17640.5 "9404",2012,17777.2666666667,2014,18376.4 "9405",2012,17254.5,2014,17473.5 "9406",2012,17553.3333333333,2014,18426 "9407",2012,16885,2014,17577.7
Your instincts will work - filter the path data according to the color: features.filter(function(feature) { return color(feature.properties["value0"]) == d; }) I saved your feature paths in the variable features in the plunkrs below As the datum of each legend entry is a color, we can just filter the paths based on which datum would produce the same color when scaled. We could alternatively give class names or apply other indicators to filter. Color the filtered paths on the event, revert all paths on some sort anti-event. Since you haven't said what will reset the map, I'll assume if you click on the same legend entry twice in a row the map should reset (this lets you toggle between each legend entry). To do so we'll need to keep track of which legend entry is currently in focus: var highlighted = ""; Then we just listen for a click event on the legend entry and: .on("click",function(d,i) { highlighted = ""; //reset // revert map back to default state } else { highlighted = d; // filter features to highlight certain ones. }) Altogether that might look like: .on("click",function(d,i) { // clicking an active entry: reset: if(highlighted == d) { // reset opacity on each path: features.style("opacity",1); // reset legend entries' fills: legend.selectAll("rect") .style("fill",function(d) { return d; }); // reset highlight variable since nothing is highlighted highlighted = ""; } // clicking a different entry: highlight that entry: else { //update highlighted variable highlighted = d; // set opacity low for all features, filter for chosen features and style accordingly: features.style("opacity",0.2) .filter(function(f) { return color(f.properties["value0"]) == d; }) .style("opacity",1); // hollow legend entries legend.selectAll("rect") .style("fill","white") // fill selected option: d3.select(this).select("rect") .style("fill",function(d) { return d;}); } }) Which looks something like: (I'm formatting the legend entries to show what is highlighted - I changed your stroke to accomodate this) Here's an updated plunkr. If you want to be able to toggle multiple legend items at once, then the logic gets a bit more detailed and the highlighted variable becomes an array As an alternative with mouseover/off events rather than clicks (so no need to track what is actively shown), here's a slightly different approach using the same principles: plunkr
D3.js adding/removing data pie chart slices
I have an input control that should on the key up event on the control either add or subtract a slice from a pie chart depending on if you hit the left or right arrow keys. It doesn't really work as expected because it seems that the new pie slice is sometimes being taken out of existing pie slices and the entire chart is not being recalculated. I'm not sure if I'm messing up the enter or the exit selection. Help is appreciated, TIA. fiddle http://jsfiddle.net/jaqj3usb/ pertinent code function removeSlices(n){ var i = -1; while(++i < n){ data.pop(); } paths.data(pie(data)).exit().remove(); paths.data(pie(data)).attr('d',arc).attr('transform','translate(100,200)') } function changeSlices(){ console.log('woot'); var shouldAddSlice = d3.event.target.valueAsNumber > data.length, numDifference = Math.abs(data.length - d3.event.target.valueAsNumber); if(shouldAddSlice){ addSlices(numDifference); } else{ removeSlices(numDifference); } } sliceSlider.on('keyup',changeSlices);
I am also new to D3js, trying to learn. I used jQuery for handling keyup events. I did some changes, so left arrow adds and right arrow subtracts slices. passed jquery as in argument to self executing function (function(d3, $) { })(window.d3, $); In addSlices() changed paths .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i] }); to paths.data(pie([])).exit().remove(); paths = svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i]; }); above code deletes and redraws the pie. full code: (function(d3,$){ var svg = d3.select('body').append('svg').attr({ height: 500, width: 500, id: 'mySvg' }); var data = [10,20,30]; var sliceSlider = d3.select('body').append('input').attr({ type: 'range', max: 10, min: 1, value : data.length }); var colors=['orange','blue','steelblue','green','red','yellow','purple','pink','indigo']; var pie = d3.layout.pie(); pie.value(function(d){ return d}); var arc = d3.svg.arc().innerRadius(10).outerRadius(100); var paths = svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i] }); function addSlices(n){ var i = -1; function randomBetween(min,max){ return Math.floor(Math.random()*(max-min+1)+min); } while(++i <n){ data.push(randomBetween(10,50)); } paths.data(pie([])).exit().remove(); paths = svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i]; }); } function removeSlices(n){ var i = -1; while(++i < n){ data.pop(); } paths.data(pie(data)).exit().remove(); paths.data(pie(data)).attr('d',arc).attr('transform','translate(100,200)'); } function changeSlices(){ console.log('woot'); var max=$("input[type='range']").attr("max")-data.length; var shouldAddSlice = max > data.length; if(shouldAddSlice){ addSlices(1); } } $(document).keyup(function(e) { switch(e.which) { case 37: // left changeSlices(); break; case 39: // right removeSlices(1); break; default: return; // exit this handler for other keys } e.preventDefault(); // prevent the default action (scroll / move caret) }); })(window.d3,$); example : http://jsfiddle.net/jaqj3usb/2/
Here is first variant (I think this is correct), base on this please add comments because you are not computing correctly from the start svg's added to the page. You can remove individual pie slice like this but this will is not update correct your plate: svg.selectAll('path')[0][pos].remove(); where pos 0 < data.length (in your original code not correct) Adding in this way you are overlapping unmoved slices: paths .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i] }); Anyhow: <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Eat my pie</title> <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script> <script type='text/javascript'> window.onload=function(){ /** * Created by cecild on 5/21/2015. * Updated by SilentTremor 5/25/2015. */ (function(d3){ svg = d3.select('body').append('svg').attr({ height: 800, width: 900, id: 'mySvg' }); var data = [10]; var sliceSlider = d3.select('body').append('input').attr({ type: 'range', max: 10, min: 1, value : data.length }); var colors=['orange','blue','steelblue','green','red','yellow','purple','pink','indigo']; var pie = d3.layout.pie(); pie.value(function(d){ return d}); var arc = d3.svg.arc().innerRadius(10).outerRadius(100); var paths = svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i] }); function addSlices(n){ var i = -1; function randomBetween(min,max){ return Math.floor(Math.random()*(max-min+1)+min); } while(++i <n){ data.push(randomBetween(10,50)); } svg.selectAll("path").remove(); paths = svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i] }); } function removeSlices(n){ var i = -1; while(++i < n){ data.pop(); } svg.selectAll("path").remove() paths = svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') .attr('d',arc) .attr('transform','translate(100,200)') .attr('fill',function(d,i){ return colors[i] }); } function changeSlices(){ var shouldAddSlice = d3.event.target.valueAsNumber > data.length, numDifference = Math.abs(data.length - d3.event.target.valueAsNumber); if(shouldAddSlice){ addSlices(numDifference); } else{ removeSlices(numDifference); } } sliceSlider.on('keyup',changeSlices); })(window.d3); } </script> </head> <body> </body> </html>
In the same way that you use this code: svg.selectAll('path').append('g') .data(pie(data)) .enter() .append('path') You can use: svg.selectAll('path').append('g') .data(pie(data)) .exit() .remove() This should remove pie graph elements which no longer have data associated with them.
how to do a simple looping carousel of svg:g elements with D3.js
I am trying to make a scrollable list that is part of a bigger d3.js generated chart. clicking on list item acivates changes in the rest of the chart. How would you make a simple animated looping carousel of svg:g elements with D3.js using the reusable chart pattern ? Wired to jQuery-mousewheel or some forward and back buttons for example. http://jsbin.com/igopix/2/edit NameLoop = function () { var scroll = 0; function chart(selection) { selection.each(function (data) { var len = data.length, scroll = scroll % len + len; // keep scroll between 0 <-> len var nameNodes = d3.select(this).selectAll("g") .data(data, function(d){return d.ID;} ); var nameNodesEnter = nameNodes.enter().append("g") .attr("class", "nameNode") .attr("transform", function(d, i) { // implement scroll here ?? return "translate(30," + (i+1)*20 + ")"; }) .append("text") .text(function(d){return d.ID;}); }); return chart; } chart.scroll = function(_) { if (!arguments.length) return scroll; scroll = _; return chart; }; return chart; }; data = [{ID:"A"},{ID:"B"},{ID:"C"},{ID:"D"},{ID:"E"}]; var svg = d3.select("body").append("svg") .attr("width", 200) .attr("height",200) .attr("id","svg"); var nameloop = NameLoop(); d3.select("#svg").datum(data).call(nameloop); var body = d3.select("body").append("div"); body.append("span").on("click",function(d){ scroll(1) }).html("forward "); body.append("span").on("click",function(d){ scroll(-1) }).html("back");