Edge on interactive d3 visualization - javascript
I'm very new to d3 and I found this code for some visualization I'm working on.
I ommited most of the data to fit in this page more smoothly.
Basically, what I want to do is make the edges of the bars appear only for the selected variable when you click on it, right now, whenever you select one variable the edges for the others are shown so it looks horrible. Much help would be appreciated!
Thanks!
<!DOCTYPE html>
<meta charset="utf-8">
<style>
text{
font-size:12px;
}
.mainBars rect{
shape-rendering: auto;
fill-opacity: 0;
stroke-width: 0.5px;
stroke: rgb(0, 0, 0);
stroke-opacity: 0;
}
.subBars{
shape-rendering:crispEdges;
}
.edges{
stroke:black;
stroke-width: .4px:
fill-opacity:0.5;
}
.header{
text-anchor:middle;
font-size:18px;
font-weight: bold;
line-height: 1.5;
}
line{
stroke:red;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://vizjs.org/viz.v1.1.0.min.js"></script>
<script>
var data=[['CA', 'Wheat', 2441900000.0, 2441900000.0],
['CO', 'Alfalfa', 4410000000.0, 4410000000.0],
['KS', 'Sorghum', 13300000000.0, 13300000000.0],
['TX', 'Sorghum', 12500000000.0, 12500000000.0],
['WY', 'Safflower', 5655522.245, 5655522.245]];
//Create array below, one color per state.
//There's probably a programmatic way to use a d3 color palette
//to just automatically do it instead of listing 51 colors individually.
//e.g. d3.scale.category10(), also
// http://stackoverflow.com/questions/20847161/how-can-i-generate-as-many-colors-as-i-want-using-d3
var color ={KS:"#3366CC", WY:"#DC3912", CA:"#FF9900", CO:"#109618", TX:"#990099", IA:"#0099C6"};
var svg = d3.select("body").append("svg").attr("width", 960).attr("height", 800);
svg.append("text").attr("x",250).attr("y",70)
.attr("class","header").text("Crop Acreage by State - 2015");
//svg.append("text").attr("x",750).attr("y",70)
// .attr("class","header").text("Duplicate");
var g =[svg.append("g").attr("transform","translate(150,100)")
,svg.append("g").attr("transform","translate(650,100)")];
var bp=[ viz.bP()
.data(data)
.min(12)
.pad(0.5)
.height(600)
.width(300)
.barSize(35)
.fill(d=>color[d.primary])
// ,viz.bP()
// .data(data)
// .value(d=>d[3])
// .min(12)
// .pad(1)
// .height(600)
// .width(200)
// .barSize(35)
// .fill(d=>color[d.primary])
];
[0,1].forEach(function(i){
g[i].call(bp[i])
g[i].append("text").attr("x",-50).attr("y",-8).style("text-anchor","middle").text("State");
g[i].append("text").attr("x", 250).attr("y",-8).style("text-anchor","middle").text("Crop");
g[i].append("line").attr("x1",-100).attr("x2",0);
g[i].append("line").attr("x1",200).attr("x2",300);
g[i].append("line").attr("y1",700).attr("y2",700).attr("x1",-100).attr("x2",0);
g[i].append("line").attr("y1",610).attr("y2",610).attr("x1",200).attr("x2",300);
g[i].selectAll(".mainBars")
.on("mouseover",mouseover)
.on("mouseout",mouseout);
g[i].selectAll(".mainBars").append("text").attr("class","label")
.attr("x",d=>(d.part=="primary"? -30: 30))
.attr("y",d=>+6)
.text(d=>d.key)
.attr("text-anchor",d=>(d.part=="primary"? "end": "start"));
g[i].selectAll(".mainBars").append("text").attr("class","perc")
.attr("x",d=>(d.part=="primary"? -100: 100))
.attr("y",d=>+6)
.text(function(d){ return d3.format("0.0%")(d.percent)})
.attr("text-anchor",d=>(d.part=="primary"? "end": "start"));
});
function mouseover(d){
[0,1].forEach(function(i){
bp[i].mouseover(d);
g[i].selectAll(".mainBars").select(".perc")
.text(function(d){ return d3.format("0.0%")(d.percent)});
});
}
function mouseout(d){
[0,1].forEach(function(i){
bp[i].mouseout(d);
g[i].selectAll(".mainBars").select(".perc")
.text(function(d){ return d3.format("0.0%")(d.percent)});
});
}
d3.select(self.frameElement).style("height", "800px");
</script>
</body>
</html>
remove the .edges style
.edges{
stroke:black;
stroke-width: .4px;
fill-opacity:0.5;
}
viz animates the fill-opacity instead of opacity
Related
d3.js chart rendering at bottom of wordpress page
Why is my js chart rendering at the bottom of the page and not in the body? I've used tons of these within my site with no problems but this one doesn't seem to want to go where desired. Thoughts? Thank you in advance! www.wcsddata.net/data-topics/jttest/ <center><!DOCTYPE html> <meta charset="utf-8"> <style> text{ font-size:12px; } .mainBars rect{ shape-rendering: auto; fill-opacity: 0; stroke-width: 0.5px; stroke: rgb(0, 0, 0); stroke-opacity: 0; } .subBars{ shape-rendering:crispEdges; } .edges{ stroke:none; fill-opacity:0.5; } .header{ text-anchor:middle; font-size:16px; } </style> <script src="https://d3js.org/d3.v4.min.js"></script> <script src="http://vizjs.org/viz.v1.1.0.min.js"></script> <script> var data=[['Lite','CA',16,0], ['Small','CA',1278,4], ['Medium','CA',27,0], ['Plus','CA',58,0], ['Grand','CA',1551,15], ['Elite','CA',141,0], ['Lite','AZ',5453,35], ['Small','AZ',683,1], ['Medium','AZ',862,0], ['Grand','AZ',6228,30], ['Lite','AL',15001,449], ['Small','AL',527,3], ['Medium','AL',836,0], ['Plus','AL',28648,1419], ['Grand','AL',3,0], ['Lite','CO',13,0], ['Small','CO',396,0], ['Medium','CO',362,0], ['Plus','CO',78,10], ['Grand','CO',2473,32], ['Elite','CO',2063,64], ['Medium','DE',203,0], ['Grand','DE',686,2], ['Elite','DE',826,0], ['Lite','KS',1738,110], ['Small','KS',12925,13], ['Medium','KS',15413,0], ['Small','GA',2166,2], ['Medium','GA',86,0], ['Plus','GA',348,3], ['Grand','GA',4244,18], ['Elite','GA',1536,1], ['Small','IA',351,0], ['Grand','IA',405,1], ['Small','IL',914,1], ['Medium','IL',127,0], ['Grand','IL',1470,7], ['Elite','IL',516,1], ['Lite','IN',43,0], ['Small','IN',667,1], ['Medium','IN',172,0], ['Plus','IN',149,1], ['Grand','IN',1380,5], ['Elite','IN',791,23], ['Small','FL',1,0], ['Grand','FL',1,0], ['Small','MD',1070,1], ['Grand','MD',1171,2], ['Elite','MD',33,0], ['Plus','TX',1,0], ['Small','MS',407,0], ['Medium','MS',3,0], ['Grand','MS',457,2], ['Elite','MS',20,0], ['Small','NC',557,0], ['Medium','NC',167,0], ['Plus','NC',95,1], ['Grand','NC',1090,5], ['Elite','NC',676,6], ['Lite','NM',1195,99], ['Small','NM',350,3], ['Medium','NM',212,0], ['Grand','NM',1509,8], ['Lite','NV',3899,389], ['Small','NV',147,0], ['Medium','NV',455,0], ['Plus','NV',1,1], ['Grand','NV',4100,16], ['Lite','OH',12,0], ['Small','OH',634,2], ['Medium','OH',749,0], ['Plus','OH',119,1], ['Grand','OH',3705,19], ['Elite','OH',3456,25], ['Small','PA',828,2], ['Medium','PA',288,0], ['Plus','PA',141,0], ['Grand','PA',2625,7], ['Elite','PA',1920,10], ['Small','SC',1146,2], ['Medium','SC',212,0], ['Plus','SC',223,4], ['Grand','SC',1803,6], ['Elite','SC',761,8], ['Small','TN',527,0], ['Medium','TN',90,0], ['Grand','TN',930,4], ['Elite','TN',395,1], ['Lite','ME',7232,58], ['Small','ME',1272,0], ['Medium','ME',1896,0], ['Plus','ME',1,0], ['Grand','ME',10782,33], ['Elite','ME',1911,3], ['Small','VA',495,0], ['Medium','VA',32,0], ['Plus','VA',7,0], ['Grand','VA',1557,12], ['Elite','VA',24,0], ['Small','WA',460,1], ['Plus','WA',88,3], ['Grand','WA',956,3], ['Small','WV',232,0], ['Medium','WV',71,0], ['Grand','WV',575,2], ['Elite','WV',368,3] ]; var color ={Elite:"#3366CC", Grand:"#DC3912", Lite:"#FF9900", Medium:"#109618", Plus:"#990099", Small:"#0099C6"}; var svg = d3.select("body").append("svg").attr("width", 960).attr("height", 800); svg.append("text").attr("x",250).attr("y",70) .attr("class","header").text("Sales Attempt"); svg.append("text").attr("x",750).attr("y",70) .attr("class","header").text("Sales"); var g =[svg.append("g").attr("transform","translate(150,100)") ,svg.append("g").attr("transform","translate(650,100)")]; var bp=[ viz.bP() .data(data) .min(12) .pad(1) .height(600) .width(200) .barSize(35) .fill(d=>color[d.primary]) ,viz.bP() .data(data) .value(d=>d[3]) .min(12) .pad(1) .height(600) .width(200) .barSize(35) .fill(d=>color[d.primary]) ]; [0,1].forEach(function(i){ g[i].call(bp[i]) g[i].append("text").attr("x",-50).attr("y",-8).style("text-anchor","middle").text("Channel"); g[i].append("text").attr("x", 250).attr("y",-8).style("text-anchor","middle").text("State"); g[i].append("line").attr("x1",-100).attr("x2",0); g[i].append("line").attr("x1",200).attr("x2",300); g[i].append("line").attr("y1",610).attr("y2",610).attr("x1",-100).attr("x2",0); g[i].append("line").attr("y1",610).attr("y2",610).attr("x1",200).attr("x2",300); g[i].selectAll(".mainBars") .on("mouseover",mouseover) .on("mouseout",mouseout); g[i].selectAll(".mainBars").append("text").attr("class","label") .attr("x",d=>(d.part=="primary"? -30: 30)) .attr("y",d=>+6) .text(d=>d.key) .attr("text-anchor",d=>(d.part=="primary"? "end": "start")); g[i].selectAll(".mainBars").append("text").attr("class","perc") .attr("x",d=>(d.part=="primary"? -100: 80)) .attr("y",d=>+6) .text(function(d){ return d3.format("0.0%")(d.percent)}) .attr("text-anchor",d=>(d.part=="primary"? "end": "start")); }); function mouseover(d){ [0,1].forEach(function(i){ bp[i].mouseover(d); g[i].selectAll(".mainBars").select(".perc") .text(function(d){ return d3.format("0.0%")(d.percent)}); }); } function mouseout(d){ [0,1].forEach(function(i){ bp[i].mouseout(d); g[i].selectAll(".mainBars").select(".perc") .text(function(d){ return d3.format("0.0%")(d.percent)}); }); } d3.select(self.frameElement).style("height", "800px"); </script>
problem is your JS selector, you need to select #content. change var svg = d3.select("body").append("svg").attr("width", 960).attr("height", 800); to: var svg = d3.select("#content").append("svg").attr("width", 960).attr("height", 800); this will show your charts in desired area. in order to center the charts you need to change the width and height: var svg = d3.select("#content").append("svg").attr("width", 600).attr("height", auto); then create a <div id="mycenterdiv" style="text-align:center; width: 100%;"> </div> in your wordpress page and then target that div (change the select) var svg = d3.select("#mycenterdiv").append("svg").attr("width", 600).attr("height", auto);
Incorrect color selection of regions in the map
I don't understand why the color of legend's labels does not always correspond to the color in the map in my code: This is my code (that is the modification of this code). The file provincias.json is available here: <!DOCTYPE html> <meta charset="utf-8"> <style> .nombre{ stroke: #000; stroke-width: 0.5px } .graticule { fill: none; stroke: #777; stroke-width: .5px; stroke-opacity: .5; } .legendLinear { font-family: "Lato"; fill:#c2b59b; } .legendTitle { font-size: 1em; } #tooltip { position: absolute; top: 0; left: 0; z-index: 10; margin: 0; padding: 10px; width: 200px; height: 70px; color: white; font-family: sans-serif; font-size: 1.0em; font-weight: bold; text-align: center; background-color: rgba(0, 0, 0, 0.55); opacity: 0; pointer-events: none; border-radius:5px; transition: .2s; } </style> <body> <div id="container"> <div id="tooltip"> </div> </div> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-composite-projections/0.3.5/conicConformalSpain-proj.min.js"></script> <script> var width = 1000, height = 900; var projection = d3.geo.conicConformalSpain() var graticule = d3.geo.graticule().step([2, 2]); var path = d3.geo.path() .projection(projection); var svg = d3.select("#container").append("svg") .attr("width", width) .attr("height", height); svg.append("path") .datum(graticule) .attr("class", "graticule") .attr("d", path); d3.json("provincias.json", function(error, provincias) { d3.json("hdi.json", function(error, hdi) { var land = topojson.feature(provincias, provincias.objects.provincias); var color = d3.scale.linear() .domain([0, 10, 1000, 10000, 100000, 300000]) .range(["#feebe2","#e5d1ff","#ba93ef", "#8D4CE5","#6100E5","#C94D8C"]); //#feebe2 svg.selectAll(".nombre") .data(land.features) .enter() .append("path") .attr("d", path) .attr("class","nombre") .style("fill",function(d){ return color(hdi[d.properties.nombre]) }) .on("mouseover", function(d){ //Show the tooltip var x = d3.event.pageX; var y = d3.event.pageY - 40; d3.select("#tooltip") .style("left", x + "px") .style("top", y + "px") .style("opacity", 1) .text(d.properties.nombre + "," + hdi[d.properties.nombre]); }) .on("mouseout", function(){ //Hide the tooltip d3.select("#tooltip") .style("opacity", 0); }); svg .append("path") .style("fill","none") .style("stroke","#000") .attr("d", projection.getCompositionBorders()); d3.select("svg").append("g") .attr("class", "legendLinear") .attr("transform", "translate(100,500)"); var legendLinear = d3.legend.color() .title("...") .shapeHeight(20) .shapeWidth(90) .shapeRadius(10) .cells([0, 10, 1000, 10000, 100000, 300000]) .orient("horizontal") .labelFormat(d3.format(".00f")) .labelAlign("start") .scale(color); svg.select(".legendLinear") .call(legendLinear); }); }); </script> The content of hdi.json is the following: {"Coruña, A":9, "Alicante":158, "Albacete":3,"Almería":0,"Asturias":13,"Álava":12,"Ávila":0, "Badajoz":10,"Balears, Illes":331,"Barcelona":250000,"Burgos":5, "Cantabria":12,"Castellón":316,"Ceuta":9,"Ciudad Real":9,"Cádiz":9,"Cuenca":4, "Córdoba":11,"Cáceres":2,"Girona":21808,"Jaén":0, "Granada":9,"Huelva":3,"Huesca":74, "León":5,"Lleida":9672,"Lugo":3, "Madrid":507,"Murcia":24,"Málaga":25,"Palencia":2,"Pontevedra":6, "Navarra":23,"Salamanca":6,"Segovia":4,"Sevilla":16,"Soria":2, "Santa Cruz de Tenerife":16,"Tarragona":22790, "Teruel":23,"Toledo":4,"Valladolid":44, "Valencia":423,"Vizcaya":19,"Zamora":0,"Zaragoza":56,"Guipúzcoa":21, "Guadalajara":5,"Jaen":2,"Rioja, La": 12, "Palmas, Las": 10,"Ourense":2} The particular problem is that Tarragona that has the value 22790 is colored in the same color as Lleida that has the value 9672. However, according to my code, 22790 (Tarragona) is smaller than 100000 and bigger than 10000, so it should be colored in #6100E5, but it's colored in #8D4CE5. But, for example, 9672 (Lleida) is smaller than 10000, so it should be colored in #8D4CE5 (and it is colored in this color, so it's ok).
You shouldn't be using a linear scale, by definition it has a continuous range and will interpolate between the colors. What you are describing is a threshold scale. It has a discrete range mapped to subsets of domain values. Further, you must call it with a range that's N + 1 of the domain, so, this is what you should be after: var color = d3.scale.threshold() .domain([10, 1000, 10000, 100000, 30000]) .range(["#feebe2","#e5d1ff","#ba93ef", "#8D4CE5","#6100E5","#C94D8C"]); Here's an example creating the legend using a threshold scale and d3-legend. <!DOCTYPE html> <html> <head> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.7.0/d3-legend.min.js"></script> </head> <body> <svg></svg> <script> var color = d3.scale.threshold() .domain([10, 1000, 10000, 100000, 300000]) .range(["#feebe2", "#e5d1ff", "#ba93ef", "#8D4CE5", "#6100E5", "#C94D8C"]); var svg = d3.select("svg"); svg.append("g") .attr("class", "legendLog") .attr("transform", "translate(20,20)"); var logLegend = d3.legend.color() .labels([0, 10, 1000, 10000, 100000, 300000]) .scale(color); svg.select(".legendLog") .call(logLegend); </script> </body> </html>
Actually it works as expected. The exact colors of Lleida and Tarragona are different, the former being #8f4fe5, the latter #8741e5. Because of the linear scales you use these colors are calculated as: ((9672-1000) * #8d4ce5 + (10000-9672) * #ba93ef)/(10000-1000) = #8f4fe5 ((22790-10000) * #6100e5 + (100000-22790) * #8d4ce5)/(100000-10000) = #8741e5 Intuitively, your problem is that 9672 is much closer to 10000 as to 1000, and 22790 is also much closer to 10000 than to 100000, so even if one of them is below 10000, and the other one above it, they are still closer to it, than to the other ends of the ranges. As Mark suggested in his answer, probably you do not want to use continuous linear scales.
relocate d3 map to center of screen no matter the device
I've got the following d3 map: but as you can see it's all bunched up there in the left corner of the screen- this is sub opimal- ideally I would like it to be centered. How can I achieve this? I guess it should be easy but every time I google something like "center align d3 map" I get things about zooming :/ maybe I need to create a div or something? the code is here on my GitHub also below- it's pretty well commented. <!DOCTYPE html> <html lang='en'> <head> <meta charset='utf-8'> <style> .border { stroke: #000; fill: none; } .graticule { fill: none; stroke: #777; stroke-width: .5px; stroke-opacity: .5; } div.tooltip { position: absolute; text-align: center; width: 84px; height: 64px; padding: 2px; font: 12px sans-serif; background: lightgrey; border: 0px; border-radius: 8px; pointer-events: none; } </style> </head> <body> <h1>Administrative Sub-Regions of Europe</h1> <!-- this is the form at the bottom to change the NUTS --> <form> <select id="json_sources" name="json_sources" > <option value ="nuts0" selected >Source 0</option> <option value ="nuts1" >Source 1</option> <option value ="nuts2" >Source 2</option> <option value ="nuts3" >Source 3</option> </select> <form> <!-- spinner --> <script src='https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.0.1/spin.min.js'></script> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> <script src="http://d3js.org/colorbrewer.v1.min.js"></script> <script src="https://cdn.rawgit.com/rveciana/d3-composite-projections/v0.2.0/composite-projections.min.js"></script> <!-- why do we need this? --> <section id='chart'> </section> <script> var div = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); var width = 600, height = 500; var projection = d3.geo.conicConformalEurope(); var graticule = d3.geo.graticule(); var path = d3.geo.path() .projection(projection); // Find new colours here: http://colorbrewer2.org/ var scale = d3.scale .quantize() .domain([10,60]) .range(colorbrewer.PuRd[3]); var svg = d3.select("body") .append("svg") .attr("width", width, "100%") .attr("height", height, "100%") .call( d3. behavior. zoom(). on("zoom", function () { svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")") } ) ) .on("dblclick.zoom", null) .append("g") //what the hell does this do? svg.append("path") .datum(graticule) .attr("class", "graticule") .attr("d", path); // pretty self spoken var dropdown = d3.select("#json_sources") // config references SPINNER RELATED var chartConfig = { target : 'chart', data_url : './nuts0.json', width: 600, height: 500, val: 90 }; // loader settings SPINNER RELATED var opts = { lines: 9, // The number of lines to draw length: 9, // The length of each line width: 5, // The line thickness radius: 14, // The radius of the inner circle color: '#EE3124', // #rgb or #rrggbb or array of colors speed: 1.9, // Rounds per second trail: 40, // Afterglow percentage className: 'spinner', // The CSS class to assign to the spinner }; // SPINNER RELATED var target = document.getElementById(chartConfig.target); // KICK OFF callback function wrapped for loader in 'init' function function init() { // trigger loader initial spinner var spinner = new Spinner(opts).spin(target); // load json data and trigger callback d3.json(chartConfig.data_url, function(data) { // stop spin.js loader spinner.stop(); // instantiate chart within callback chart(data); }); } //call that init function we define above init(); //here where all the real stuff happens //in fact all that init stuff is just legacy //from the spinner example function chart(data) { //start of map making function var change = function() { // trigger loader of the spinner var spinner = new Spinner(opts).spin(target); // did they change the NUTS? var source = dropdown.node().options[dropdown.node().selectedIndex].value; //necessary data processing var str1 = source; var str2 = ".json"; var file = str1.concat(str2); console.log(file); d3.json(file, function(error, europe) { d3.csv("povertry_rate.csv", function(error, povrate) { //change the map to apadpt to the nuts file if (source == "nuts1") { var land = topojson.feature(europe, europe.objects.nuts1); } else if (source == "nuts2") { var land = topojson.feature(europe, europe.objects.nuts2); } else if (source == "nuts3") { var land = topojson.feature(europe, europe.objects.nuts3); } else if (source == "nuts0") { var land = topojson.feature(europe, europe.objects.nuts0); } data = {}; povrate.forEach(function(d) { data[d.GEO] = d['2013']; }); //clear way for the regeneration d3.selectAll("path").remove(); //recreate those map lines svg.append("path") .datum(graticule) .attr("class", "graticule") .attr("d", path); // stop spin.js loader spinner.stop(); console.info(data); svg .selectAll("path") .data(land.features) .enter() .append("path") .attr("d", path) .style("stroke","#000") .style("stroke-width",".5px") .style("fill",function(d){ var value = data[d.id]; if (isNaN(value)){ value = data[d.id.substring(0,2)]; } if (isNaN(value)){ return "#fff"; } return scale(value); }) .on("mouseover", function(d,i) { var value = data[d.id]; if (isNaN(value)){ value = data[d.id.substring(0,2)]; } div.transition() .duration(200) .style("opacity", 0.9); div.html("<b>"+d.properties.name+"</b><br/>" + value + "%") .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d,i) { div.transition() .duration(500) .style("opacity", 0); }); svg .append("path") .style("fill","none") .style("stroke","#000") .attr("d", projection.getCompositionBorders()); }); }) } dropdown.on("change", change) change(); //call that change function once } </script> </body> </html>
Not really a d3 question just a little CSS: svg { display: block; margin: auto; border: 1px solid gray; }
inexplicable inability to render city name labels on a d3.js map: out of scope NAME?
I'm following the canonical "Let’s Make a Map" tutorial- but to spice things up I'm melding it with one about Germany- so I'm working with slightly different data. Things are so far working out- barring this minor hiccup- but now I've come to the section "#Displaying Places" which is where you're supposed to show the names of the cities on the map. The problem is happening in the following line: .text(function(d) { if (d.properties.name!=="Berlin" && d.properties.name!=="Bremen"){ //for some reason this is undefined console.log(d.properties.name); return d.properties.name; } }) The value of that console.log(d.properties.name); is always undefined and I can't figure out why! I suppose it's because name is out of scope for d- but I don't know how to fix it. Is that right? If so- how to fix it? if not- what is the real problem? Here is what my code looks like- it's pretty concise: <!DOCTYPE html> <meta charset="utf-8"> <style> .subunit{fill:#fff;} .subunit.Nordrhein-Westfalen{ fill: #aba; } .subunit.Baden-Württemberg{ fill: #bab; } .subunit.Hessen{ fill: #bcb; } .subunit.Niedersachsen{ fill: #cbc; } .subunit.Thüringen{ fill: #cdc; } .subunit.Hamburg{ fill: #dcd; } .subunit.Schleswig-Holstein{ fill: #ded; } .subunit.Rheinland-Pfalz{ fill: #ede; } .subunit.Saarland{ fill: #efe; } .subunit.Sachsen-Anhalt{ fill: #fef; } .subunit.Brandenburg{ fill: #aaa; } .subunit.Mecklenburg-Vorpommern{ fill: #bbb; } .subunit.Bayern { fill: #ccc; } .subunit.Sachsen { fill: #ddd; } .subunit.Bremen { fill: #eee; } .subunit.Berlin { fill: #fff; } .subunit-boundary { fill: none; stroke: #777; stroke-dasharray: 2,2; stroke-linejoin: round; } .place, .place-label { fill: #444; font-size:14px; } text { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 20px; pointer-events: none; } </style> <body> <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script> <script src="//d3js.org/topojson.v1.min.js"></script> <script> var width = 960, height = 1160; var projection = d3.geo.mercator() .center([10.5, 51.35]) .scale(3000) .translate([width / 2, height / 2]); var path = d3.geo.path() .projection(projection); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); d3.json("de.json", function(error, de) { //colouring the different subunits svg.selectAll(".subunit") .data(topojson.feature(de, de.objects.subunits).features) .enter().append("path") .attr("class", function(d) { // console.log(d.properties.name); return "subunit " + d.properties.name; }) .attr("d", path); //adding a border to the states svg.append("path") .datum(topojson.mesh(de, de.objects.subunits, function(a,b) { if (a!==b || a.properties.name === "Berlin"|| a.properties.name === "Bremen"){ var ret = a; } return ret; })) .attr("d", path) .attr("class", "subunit-boundary"); // add small black dots for populated places svg.append("path") .datum(topojson.feature(de, de.objects.places)) .attr("d", path) .attr("class", "place"); //trying to display names of cities svg.selectAll(".place-label") .data(topojson.feature(de, de.objects.places).features) .enter().append("text") .attr("class", "place-label") .attr("transform", function(d) { //small test //console.log( "translate(" + projection(d.geometry.coordinates) + ")" ); return "translate(" + projection(d.geometry.coordinates) + ")"; }) .attr("dy", ".35em") .text(function(d) { if (d.properties.name!=="Berlin" && d.properties.name!=="Bremen"){ //for some reason this is undefined console.log(d.properties.name); return d.properties.name; } }) .attr("x", function(d) { return d.geometry.coordinates[0] > -1 ? 6 : -6; }) .style("text-anchor", function(d) { return d.geometry.coordinates[0] > -1 ? "start" : "end"; }); }); </script> Here is the data file. EDIT expected actual
Inside your .topojson you have two section: properties: names of your counties and polygons places: coordinates of the points You access the first collection with: de.objects.subunits And the second collection through: de.subunits.places After file is loaded sepearte into two different variables to use it: d3.json("de.json", function(error, de) { var counti = topojson.feature(de, de.objects.subunits) var places = topojson.feature(de, de.objects.places) then referenciate the content adding .features .data(counti.features) // <-- to draw your paths and get the .name: München or .data(places.features) // <-- to draw the circles for the cities: "coordinates": [11.573039376427117, 48.131688134368815] Mike's topojson has: { "type": "Feature", "properties": { "name": "Ayr" }, "geometry": { "type": "Point", "coordinates": [ -4.617021378468872, 55.44930882146421 ] } and you has: { "type": "Feature", "properties": {}, "geometry": { "type": "Point", "coordinates": [ 11.573039376427117, 48.131688134368815 ] } Mike's point properties looks like this: and point coordinates Your point properties: Solution: The right way Open your map on GIS software (ArcGIS-pay, Q-GIS-free) edit and correct paths and points properties and export as TopoJSON again.- Easy way Go to: geojson.io load your json and add propertie name to your point (16 points, easy cake) and save as TopoJSON again.- Now you're there correct countie info deleting one column (you has duplicate info)
#Klaujesi has explained the reason pretty well. I am just going to solve the issue by a work around. Since there is no property inside the Feature, so you can get the property from de.objects.subunits, like below. .text(function(d, i) { //here i is the index of the place. //de.objects.subunits.geometries[i].properties will give you the name that you are looking for. d.properties = de.objects.subunits.geometries[i].properties; if (d.properties.name!=="Berlin" && d.properties.name!=="Bremen"){ //for some reason this is undefined console.log(d); return d.properties.name; } }) working code here
D3 line graph appearing as area graph
I have drawn a line graph and area under the line is appears to be colored to make it appear like a area graph. The code is shown below <!DOCTYPE html> <html> <head> <style type="text/css"> body { font: 12px Arial; } path { stroke-width: 1; stroke : 1; } .axis path,.axis line { fill: none; stroke: grey; stroke-width: 1; shape-rendering: crispEdges; } </style> <script type="text/javascript" src="d3.min.js"></script> <script type="text/javascript" src="jquery-1.8.0.js"></script> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <script type="text/javascript"> var baseSvg = d3.select("body") .append("svg") .attr("height",800) .attr("width",800) .append("g") .attr("transform","translate(50,50)"); $.ajax({ method : 'GET', url:"URL", //Called my URL here success:function(data){ var res = data.d.results; /* res.forEach(function(d){ console.log(new Date(parseInt(d.DATE_SQL.substring(6)))); }) */ buildTrend(res); } }) ; function buildTrend(res) { var x = d3.time.scale().range([ 50, 700 ]); var y = d3.scale.linear().range([ 500, 0 ]); res.forEach(function(d){ d.DATE_SQL = new Date(parseInt(d.DATE_SQL.substring(6))); }); var line = d3.svg.line().interpolate("basis").x(function(d) { return x(d.DATE_SQL) }).y(function(d) { return y(d.M_COUNT) }); x.domain(d3.extent(res, function(d) { return d.DATE_SQL; })); y.domain([0,d3.max(res, function(d) { return d.M_COUNT; })]); var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(15); baseSvg.append("g") .attr("class", "x axis").attr("transform", "translate(0," + 500 + ")").call(xAxis) .selectAll("text").attr("transform",function(d){ return "rotate(-90)"}) .attr("dx", "-.8em").attr("dy", ".15em").style("text-anchor", "end"); var yAxis = d3.svg.axis().scale(y).orient("left").ticks(8); baseSvg.append("g") .attr("transform","translate(50,0)")// Add the Y Axis .attr("class", "y axis").call(yAxis); baseSvg.append("g") .attr("transform","translate(0,10)") .append("path") .attr("d",line(res)) .attr("stroke","blue"); } </script> </body> </html> However the result looks like this I have checked all my code to search "Black" to identify possible cause of the color and i dont find any. Maybe it is default color. Cannot figure out the reason for this. Thanks, Veera
Try adding this css to your line: path line { fill: none; stroke: #000; } I've had this happen to me in the past, if I remember correctly what is happening is that d3 thinks that the first point and the last point on the line are joined and therefore making it an area and filling it by default with the color black. If you set the fill to none and add a stroke it should fix this. Hope this helps.