d3.js selectAll for paths - javascript
I'm trying to get an D3.js interactive map that, on hovering on a certain municipality (divided into svg paths), will return the name and the number of escape room themes in said municipality. However, I can't get selectAll("path") or any variation to work on it.
Here's my code:
d3.json("data/seoul_municipalities_topo_simple.json", function(error, data) {
var features = topojson.feature(data, data.objects.seoul_municipalities_geo).features;
seoulmap.selectAll("path")
.data(features)
.enter().append("path")
.attr("class", function(d) {
console.log();
return "municipality c" + d.properties.SIG_CD
})
.attr("id", function(d) {
return d.properties.SIG_KOR_NM
})
.attr("d", path); /* the path variable holds the geoPath from my topojson file*/
});
//tooltip displays
var mouselocation;
var tooltip = d3.select(".tooltip");
var mappath = d3.selectAll("path"); /* this doesn't work */
mappath.on('mouseenter', function() {
tooltip.style('display', 'block');
let textID = this.id;
tooltip.select(".tooltip-city")
.html("<strong>" + textID + "</strong></br>");
tooltip.select(".tooltip-num")
.html("# of Themes: ");
}).on('mousemove', function() {
mouselocation = d3.mouse(d3.select('body').node());
tooltip.style("left", mouselocation[0] + 160 + "px")
.style("top", mouselocation[1] + 10 + "px");
}).on('mouseleave', function() {
tooltip.style('display', 'none');
});
when I run my site on console, each element in the svg is divided into paths that hold the class .municipality. Selecting through that doesn't work either. But if I replace the selector to something else, say "svg", works like a charm. I'm not sure what I'm doing wrong here??
(I'm using D3.js v4!)
Related
Trying to get two circles to transition simultaneously
Trying to get two circles (one red, one blue) to move to center of screen from opposite directions. Can only get the second circle to do it - unsure as to why. I tried everything from switching up the order of functions being called to switching variable names var svg = d3.select("body") .append("svg") .attr("width", 600) .attr("height", 200); var circles = svg.append('circle') .attr('cx',50).attr('cy',50).attr('r',10).style('fill','red'); var circlesTwo = svg.append('circle') .attr('cx',50).attr('cy',50).attr('r',10).style('fill','blue'); animation(); animationTwo(); function animation() { svg.transition() .duration(750) .tween("precision", function() { var area = d3.interpolateRound(0, 300); return function(t) { minArea = area(t); render(); }; }) } function animationTwo() { svg.transition() .duration(750) .tween("precision", function() { var area = d3.interpolateRound(600, 300); return function(t) { minArea = area(t); renderTwo(); }; }) } function render() { circles.attr('cx',minArea); } function renderTwo() { circlesTwo.attr('cx',minArea); } <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> Expected results are two circles coming to their respective positions (from off screen originally). Actual results are I am only getting my blue circle to work.
Applying the transitions to the SVG selection is not a very idiomatic D3: you should apply them to the elements that are moving (i.e., the circles). That, by the way, is the cause of the problem you're facing: one transition is cancelling the other. This happens because since your transitions have no name, null is used (link): selection.transition([name]) <> Returns a new transition on the given selection with the specified name. If a name is not specified, null is used. Then, because all of them have the same name (null), the last one cancels the first one: The starting transition also cancels any pending transitions of the same name on the same element that were created before the starting transition. Therefore, to apply multiple transitions to the same element, you have to name them: function animation() { svg.transition("foo") //etc... } function animationTwo() { svg.transition("bar") //etc... } Here is your code with that change: var svg = d3.select("body") .append("svg") .attr("width", 600) .attr("height", 300); var circles = svg.append('circle') .attr('cx', 50).attr('cy', 50).attr('r', 10).style('fill', 'red'); var circlesTwo = svg.append('circle') .attr('cx', 50).attr('cy', 50).attr('r', 10).style('fill', 'blue'); animation(); animationTwo(); function animation() { svg.transition("foo") .duration(750) .tween("precision", function() { var area = d3.interpolateRound(0, 300); return function(t) { minArea = area(t); render(); }; }) } function animationTwo() { svg.transition("bar") .duration(750) .tween("precision", function() { var area = d3.interpolateRound(600, 300); return function(t) { minArea = area(t); renderTwo(); }; }) } function render() { circles.attr('cx', minArea); } function renderTwo() { circlesTwo.attr('cx', minArea); } <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> Again, have in mind that I'm simply answering your question here: my advice is that you should refactor that transition code completely.
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
Dashed line doesn't work
I have a list of radio buttons indicating a country. I want that when user clicks on a radio button, the right line chart are loaded. To do so I have 4 csv files with data for each country. The csv files are like this: year,death,value 2012,Tuberculosis,NA 2011,Tuberculosis,NA 2010,Tuberculosis,301 2009,Tuberculosis,344 2008,Tuberculosis,333 2007,Tuberculosis,329 2006,Tuberculosis,350 2005,Tuberculosis,NA 2004,Tuberculosis,NA 2003,Tuberculosis,396 2002,Tuberculosis,413 2001,Tuberculosis,415 2000,Tuberculosis,460 1999,Tuberculosis,517 1998,Tuberculosis,558 1997,Tuberculosis,597 1996,Tuberculosis,609 1995,Tuberculosis,647 2012,Tetanus,NA 2011,Tetanus,NA 2010,Tetanus,17 2009,Tetanus,27 2008,Tetanus,18 ... HERE is my code. I don't know why Plunker create the error "Bad request". Anyway, this is my result: if the user clicks on Italy, then the browser loads Italy.csv file and creates the chart, if the user clicks on Hungary, then browser loads Hungary.csv file and creates the chart and so on. The problem is that in my csv files, there are some "holes" on data. For example, I haven't any data about number of deaths in Italy between 2003 and 2006 so I want to show a dashed line instead of a solid line. In my chart I'm not able to do that. In particular, I wrote code to do that but it doesn't work. Note that the missing data will change according to the countries. For some countries I have all the data and not for other countries. Also, if the user clicks on the circle (the legend) of the corresponding series disappears, the circle should turn white and the axes change to fit the current data. This doesn't work and I don't understand why. As you can see, the console doesn't show any errors. In this similar example, it works: PLUNKER I badly explained myself. With "missing data" I mean NA values. NEW PLUNKER I understand that the chart of Belgium is right. I tried to understand why the Denmark chart is that but sorry, I don't understand when you say "Code generate multiples paths for every abailable data and just ONE path for all NA data. Instead it must generate a segments for every gap on data.". The code is organized in this way: // some code... /************************************************************************** *** GET SELECTED COUNTRY AND DRAW FIRST CHART **************************** **************************************************************************/ var l_selectedCountry = document.querySelector('input[name="l_country"]:checked').value; l_createLineChart(l_selectedCountry); var l_updateradio = function() { l_selectedCountry = $('input[name=l_country]:checked', '#l_countries').val(); l_createLineChart(l_selectedCountry); } $("#l_countries").on("change", l_updateradio); /************************************************************************** *** DRAW THE RIGHT CHART BASED ON SELECTED COUNTRY ********************** **************************************************************************/ function l_createLineChart(l_selectedCountry) { // remove last chart d3.select("#l_chartcontainer") .html(""); // adds the svg canvas var svg = d3.select("#l_chartcontainer") .append("svg") .attr("width", l_width + margin.left + margin.right) .attr("height", l_height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var l_file = "./data/line_data/" + l_selectedCountry + ".csv"; /************************************************************************** *** GET RIGHT DATA ******************************************************** **************************************************************************/ d3.csv(l_file, function(l_error, l_data) { l_data.forEach(function(d) { d.year = parseDate(d.year); d.value = +d.value; }); // code about axis... /************************************************************************** *** GET ALL LINE DATA (solid & dashed) ************************************ **************************************************************************/ var l_dataNest = d3.nest() .key(function(d) { return d.death; }) .entries(l_data); console.log("l_dataNest"); console.log(l_dataNest); // code about labels... /************************************************************************** *** GET DASHED LINE DATA ************************************************** **************************************************************************/ var l_dashedData = l_getDashed(l_dataNest); // dashed line (extreme point) for each disease console.log("l_dashedData"); console.log(l_dashedData); // other code... /************************************************************************** *** DRAW SOLID LINE ******************************************************* **************************************************************************/ svg.append('g') .attr('class', 'l_line-container') .selectAll('.normal-line-paths') .data(l_dataNest) // set our data .enter() // enter the data and start appending elements .append('path') .call(l_path); // calling our path function for later use when appending lines /************************************************************************** *** DRAW DASHED LINE ****************************************************** **************************************************************************/ svg.append('g') .attr('class', 'dashed-line-container') .selectAll('.dashed-line-paths') .data(l_dashedData) .enter() .append('path') .call(l_dashedPath); // other code... }); } // code about event... function l_path(myPath) { myPath.style("fill", "none") .style("stroke", function(d) { return l_color[d.key]; }) .attr('class', function(d) { return 'normal-line-paths path-' + d.key.replace(/\s+/g, ''); }) .attr("d", function(d) { return valueline(d.values); }) .style("opacity", 0.5) .on("mouseover", l_onMouseOverLine) .on("mouseout", l_onMouseOutLine); } function l_dashedPath(myPath) { myPath.style("fill", "none") .style("stroke", function(d) { return l_color[d.key]; }) .style("stroke-width", 5) .attr("stroke-dasharray", '4') .attr('class', function(d) { return 'dashed-line-paths path-' + d.key.replace(/\s+/g, ''); }) .attr("d", function(d) { return valueline(d.values); }) .style("opacity", 0.5) .on("mouseover", l_onMouseOverLine) .on("mouseout", l_onMouseOutLine); } /** * Function to return the data points that will create the dashed lines. */ function l_getDashed(data) { return data.map(function(collection, index) { var l_startNaN = false; var l_dashed = { key: collection.key, // disease values: [] //array of death, death and year }; collection.values.forEach(function(dataPoint, index) { var l_value = dataPoint.value; var values = collection.values; if($.isNumeric(l_value) && l_startNaN) { l_startNaN = false; l_dashed.values.push(values[index]); } else { if(($.isNumeric(l_value) && l_startNaN) || (!$.isNumeric(l_value) && !l_startNaN)) { l_startNaN = true; l_dashed.values.push(values[index-1]); } } }) if((l_dashed.values.length % 2)) { l_dashed.values.pop(); } return l_dashed; }); } If I comment this piece of code: // apend a group element which will contain our dashed lines /*svg.append('g') .attr('class', 'dashed-line-container') .selectAll('.dashed-line-paths') .data(l_dashedData) .enter() .append('path') .call(l_dashedPath);*/ I get: and if I comment: // apend a group element which will contain our lines /*svg.append('g') .attr('class', 'l_line-container') .selectAll('.normal-line-paths') .data(l_dataNest) // set our data .enter() // enter the data and start appending elements .append('path') .call(l_path); */ I get: So there must be a problem in l_dashedPath(myPath) method. But if I print d, I get the four ends of the two portions dashed (Tuberculosis): 23, 32, 15, 16 that are correct. .attr("d", function(d) { console.log(d); return valueline(d.values); }) Also the l_getDashed(data) method seems correct to me.
Inside Plunker you can't have spaces on filename. Rename it 'United Kingdom.csv' to something with underscore (_) or so. "United_Kingdom.csv" Your function l_getdashed, don't take the next point for every dashed segment. At the end you just get a point, not a segment. I'ver re-refactory your function: function l_getDashed(data) { return data.map(function(collection, index) { var l_startNaN = false; var l_dashed = { key: collection.key, values: [] }; collection.values.forEach(function(dataPoint, index) { var l_value = dataPoint.value; var values = collection.values; if ($.isNumeric(l_value) && l_startNaN) { l_startNaN = false; l_dashed.values.push(values[index]); } else if ( !$.isNumeric(l_value) !== l_startNaN) { l_startNaN = true l_dashed.values.push(values[index-1]); } }) if (l_dashed.values.length % 2) { l_dashed.values.pop() } return l_dashed; }); } Here the update working Plunker DENMARK Your code has concept errors. Thats why you see 'Denmark' like that. Graphically: Code generate multiples paths for every abailable data and just ONE path for all NA data. Instead it must generate a segments for every gap on data.- BELGIUM Belguim is a different history. The graph is ok, your data has isolated points (red dots) and can not be dismiss. You can not draw a dashed-line from 1997-2009 (black arrow) because you'll discarding data.
Updating several d3.js cartograms in the same container
I'm trying to update 4 cartograms in the same div. First I create 4 original maps, each in its own svg, like this: function makeMaps(data){ var mapsWrapper = d3.select('#maps'); data.forEach(function(topoJSON,i){ var quantize = d3.scale.quantize() .domain([0, 1600000]) .range(d3.range(5).map(function(i) { return "q" + i; })); var layer = Object.keys(topoJSON.objects)[0] var svg = mapsWrapper.append('svg') .attr("class","mapa") .attr({ width: "350px", height: "350px" }); var muns = svg.append("g") .attr("class", "muns") .attr("id",layer) .selectAll("path"); var geometry = topoJSON.objects[layer].geometries; var carto = cartos[i] var features = carto.features(topoJSON, geometry), path = d3.geo.path() .projection(projections[i]); muns.data(features) .enter() .append("path") .attr("class", function(d) { return quantize(d.properties['POB1']); }) .attr("d", path); }); } This part works well and creates 4 maps. After this, I want to update the paths in each map with the paths calculated by cartogram.js. The problem is that I can't get to the path data in each of the maps, here's what I'm trying to do: ...some code to calculate cartogram values var cartograms = d3.selectAll(".mapa").selectAll("g").selectAll("path") cartograms.forEach(function(region,i){ region.data(carto_features[i]) .select("title") .text(function (d) { return d.properties.nom_mun+ ': '+d.properties[year]; }); In cartograms I'm getting a nested selection: an array of paths for each map, which is what I though I needed, but inside the forEach I get the error region.data() is not a function. Each region is an array of paths each of which has a data property. I've tried with several ways of selecting the paths to no avail and I'm a little lost now. Thanks for your help
Stroke-dasharray tween on multiple paths
I am projecting multiple line paths on a map and hoping to use stroke-dash interpolation on them to show path movements. I want to use the same Tween function on all the paths, but it seems as though the Tween is returning the same value for every path. All of the lines seem to be projecting fine; it's only the Tween that's causing some issue. It causes this issue, where the paths show stroke-dashes: It should instead look like the following: My lines are projected using the following standard process for a leaflet x/y conversion: var svg = d3.select(map.getPanes().overlayPane).append("svg"); var g = svg.append("g").attr("class", "leaflet-zoom-hide"); var transform = d3.geo.transform({ point: projectPoint }); var d3path = d3.geo.path().projection(transform); var toLine = d3.svg.line() .interpolate("linear") .x(function(d,i) { return applyLatLngToLayer(d).x }) .y(function(d,i) { return applyLatLngToLayer(d).y }); g.selectAll(".lineConnect").remove(); var linePath = g.selectAll(".lineConnect") .data(series) .enter() .append("path") .attr("class", "lineConnect") linePath.attr("d", toLine) And here you see the function that calls the Tween: function transition() { linePath.transition() .duration(700).attrTween("stroke-dasharray", tweenDash); } function tweenDash() { return function(t) { var l = linePath.node().getTotalLength(); interpolate = d3.interpolateString("0," + l, l + "," + l); return interpolate(t); } }
Your code assumes that you have only a single element in the selection (linePath.node()) -- you're getting the length of the first element only. You could use for example .each() to make it work for every line: function transition() { d3.select(this).transition() .duration(700).attrTween("stroke-dasharray", tweenDash); } function tweenDash() { var that = this; return function(t) { var l = that.getTotalLength(); interpolate = d3.interpolateString("0," + l, l + "," + l); return interpolate(t); } } linePath.each(transition);