Very basic syntax error, lines not drawing in d3 - d3.js

For some reason, in the last block of this code append("g) us successful, but the data bind to append lines is not. I know should just print 10 lines on top of each other, but I cannot even get them to print into the page for some reason. Can anyone see the error? Thanks very much for your help!
var w = 300;
var dataset = 10;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", w);
svg.append("line")
.attr("x1", w/2)
.attr("y1", 0)
.attr("x2", w/2)
.attr("y2", w);
svg.append("line")
.attr("x1", 0)
.attr("y1", w/2)
.attr("x2", w)
.attr("y2", w/2);
svg.append("g")
.selectAll("line")
.data(dataset)
.enter()
.append("line")
.attr("x1", 0)
.attr("y1", w/4)
.attr("x2", w/2)
.attr("y2", w/4);

dataset in .data(dataset) has to be an array so you get nothing. If you use, for example .data([dataset]) you will get one line. If you want 10 lines you can use .data(d3.range(10)) and add some color to see it/them:
svg.append("g").selectAll("line")
.data(d3.range(10))
.enter()
.append("line")
.attr("x1", 0)
.attr("y1", w/4)
.attr("x2", w/2)
.attr("y2", w/4)
.style('stroke', 'green');

Related

D3 Gradient Fill on Bar Chart - with colour scale

I have managed to apply a gradient to my bar chart and the gradient effect gives the desired result.
var gradient = svg.append("defs")
.data(data)
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", function(d) {
return colors(d.name);
})
.attr("stop-opacity", 1);
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", function(d) {
return colors(d.name);
})
.attr("stop-opacity", 0.3);
I also have a color scale that I'm using to assign colors to each category (name)
var colors = d3.scale.ordinal()
.range(["#C1D42F", "#2b328c", "#5AB88D", "#8F1F61", "#00A5D3", "#EC5D20", "#F59C28"])
This was working fine before I started to use gradient
However, now it appears that the function I'm using is only taking the first color (#C1D42F) from my range.
How can I apply the gradient as well as assign the ranged colors ?
Here is my fiddle
There are two issues related to this result
1) The gradient definition is missing the .enter() method
This is necessary to create a linearGradient element for each data point. Instead of:
var gradient = svg.append("defs")
.data(data)
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
You could use:
var gradient = svg.append("defs")
.selectAll("linearGradient") // Creates the initial selection of linear gradients
.data(data)
.enter() // Binds new linearGradient elements for each data point
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
Now, instead of having only one linearGradient element, you have one for each color. However, you will notice the problem persists, which leads to the second issue:
2) If all the linear gradients have the same ID, the code can not differentiate between colors.
Different linearGradient elements need different IDs in order to reference the data they represent. Continuing the previous example, instead of:
var gradient = svg.append("defs")
.selectAll("linearGradient") // Creates the initial selection of linear gradients
.data(data)
.enter() // Binds new linearGradient elements for each data point
.append("linearGradient")
.attr("id", "gradient")
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
You could use:
var gradient = svg.append("defs")
.selectAll("linearGradient") // Creates the initial selection of linear gradients
.data(data)
.enter() // Binds new linearGradient elements for each data point
.append("linearGradient")
.attr("id", d => `gradient${d.name}`) // Create a unique data-driven id for each linearGradient
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "00%")
.attr("spreadMethod", "pad");
And in the bars, the code can now reference the correct linearGradient according to the data:
bars.append("rect")
...
.style("fill", d => `url(#gradient${d.name})`); // picks the gradient that match the data

How to add text to a vertical line d3js

I'm trying to add text to a vertical line using d3. In principle the text is attached to the line but it is not showing. Any idea why? Here is my code and and image of the current state.Code problem
Thanks in advance!
var espanya = aggregatevalue(data)[0]['2015'];
var svg = d3.select("#UnemploymentRate")
.append("svg")
.attr("id", "chart")
.attr("width", w)
.attr("height", h);
svg.append("g")
.attr("class", "espanya line")
var lespanya = d3.select(".espanya.line")
.append("line")
.attr("class", "line")
.style("stroke-width", 2)
.style("stroke", "black")
.style("stroke-dasharray", ("3, 3"))
.style("fill", "none");
lespanya.attr("x1", padding.left + widthScale(espanya))
.attr("y1", heightScale(maximo))
.attr("x2", padding.left + widthScale(espanya))
.attr("y2", h - padding.bottom);
lespanya.append("text")
.attr("x", 486.78)
.attr("y", 300)
.text("Spain Average unemployment");
You should not append that group to the line element. You can append both text and line to .espanya.
It has to be more or less like this,
var svg = d3.select("#UnemploymentRate")
.append("svg")
.attr("id", "chart")
.attr("width", w)
.attr("height", h);
var container = svg.append("g")
.attr("class", "espanya")
var lespanya = container
.append("line")
.attr("class", "line")
.style("stroke-width", 2)
.style("stroke", "black")
.style("stroke-dasharray", ("3, 3"))
.style("fill", "none");
var text = container
.append("text")
.attr("x", 486.78)
.attr("y", 300)
.text("Spain Average unemployment");
Try this and provide a jsfiddle if it doesn't work.

D3. Why is my group translation not working?

My goal here is to translate a group of svg elements with a translation. It is not working. Here is the code:
Create an SVG container
// create svg container
canvas = d3.select("body").append("svg")
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height);
Append a translation of x=200, y=200
// apply a transform
canvas.append("g")
.attr("transform", function(d) { return scarpa.translate(200, 200); });
Add a box
// render a background
canvas.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.style("opacity", 1)
.style("fill", function(d) { return scarpa.rgb_SVG(0,255,0); });
Add a y-axis
// render y-axis
canvas.append("g")
.attr("class", "y axis")
.append("line")
.attr("stroke", function(d) { return scarpa.grey_SVG(64); })
.attr("x1", histogram.xScale(0))
.attr("y1", 0)
.attr("x2", histogram.xScale(0))
.attr("y2", canvasBBox.height);
The box + y-axis line never translates. For a sanity check I applied the translation direction to the box and it did translate. Sigh.
I am assuming the group translation implies a local coordinate system within with x = y = 0 would be the origin of the translated coordinate frame. No? What am I missing here?
The problem is, that the .append() function does not change the selection that it is called on, but returns a new selection.
Therefore the g element gets appended to the svg and the rect gets also appended to the svg and not inside the translated g element. You should see this if you inspect the svg output.
There are two possible solutions:
1: If you want to translate everything, append the g element in the first statement like so:
var canvas = d3.select("body").append("svg")
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.append("g")
.attr("transform", function(d) { return scarpa.translate(200, 200); });
canvas.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.style("opacity", 1)
.style("fill", function(d) { return scarpa.rgb_SVG(0,255,0); });
canvas.append("g")
.attr("class", "y axis")
.append("line")
.attr("stroke", function(d) { return scarpa.grey_SVG(64); })
.attr("x1", histogram.xScale(0))
.attr("y1", 0)
.attr("x2", histogram.xScale(0))
.attr("y2", canvasBBox.height);
2: If you want to append something outside of the translated group,
assign the groupselection to a new variable like so:
var canvas = d3.select("body").append("svg")
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height);
var canvasGroup = canvas.append("g")
.attr("transform", function(d) { return scarpa.translate(200, 200); });
canvasGroup.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", canvasBBox.width)
.attr("height", canvasBBox.height)
.style("opacity", 1)
.style("fill", function(d) { return scarpa.rgb_SVG(0,255,0); });
canvasGroup.append("g")
.attr("class", "y axis")
.append("line")
.attr("stroke", function(d) { return scarpa.grey_SVG(64); })
.attr("x1", histogram.xScale(0))
.attr("y1", 0)
.attr("x2", histogram.xScale(0))
.attr("y2", canvasBBox.height);

D3 vertical line graph

I have a line (& area) graph which works ok, when horizontal. But I really need it to be vertical, to stand up. I have tried all kinds of changes to the existing code. Mostly with some strange results.
Here’s the code (modified it a bit). Is there a way to change it to make the graph vertical?:
var x = d3.scale.linear().domain([1, itemCount]).range([0, width]);
var y = d3.scale.linear().domain([0, maxValue]).rangeRound([height, 0]);
// Set up linar x and y axis.
var xAxis = d3.svg.axis().scale(x).ticks(10);
var yAxis = d3.svg.axis().scale(y).ticks(2).orient("left");
// Line graph.
line = d3.svg.line()
.interpolate("basis")
.x(function (d) {
return x(d.x);
})
.y(function (d) {
return y(d.y);
});
// Create SVG element.
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
// X-Axis, to bottom.
svg.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(1," + height + ")")
.call(xAxis);
//Y-Axis
svg.append("svg:g")
.attr("class", "axis")
.attr("transform", "translate(40, 1)")
.call(yAxis);
// Horizontal axis guide lines.
svg.selectAll("line.y")
.data(y.ticks(5))
.enter()
.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", y)
.attr("y2", y)
.style("stroke", "#000000")
.style("stroke-opacity", 0.1);
// Vertical axis guide lines.
svg.selectAll("line.x")
.data(y.ticks(5))
.enter()
.append("line")
.attr("x1", x)
.attr("x2", x)
.attr("y1", 0)
.attr("y2", this.heightInside - pushDown)
.style("stroke", "#000000")
.style("stroke-opacity", 0.1);
// Set up domains. Nice ensures the domains ends on nice round values.
x.domain([dataValues[0].x, dataValues[dataValues.length - 1].x]).nice();
y.domain([d3.min(dataValues, function (d) { return (d.y); }),
d3.max(dataValues, function (d) { return (d.y); })])
.nice();
// Draw line on graph.
svg.append("svg:path")
.attr("class", "line")
.attr("d", line(dataValues))
.style("stroke", function(d) { return colors[i]; });
// Marks.
svg.selectAll("circle_" + i)
.data(dataValues)
.enter()
.append("circle")
.style("fill", function(d) { return _this.colors[i]; })
.attr("r", 4)
.attr('cx', function (d) { return x(d.x); })
.attr('cy', function (d) { return y(d.y); });

generate circle for each line of CSV D3.js

I'm trying to read in a CSV and generate a circle for each line using d3.js.
[I'd prefer not to use a callback function but that's a different question.]
I'm able to create a table for each line of data following: http://christopheviau.com/d3_tutorial/
but I can't seem to generate a circle for each line:
d3.text("test.csv", function(datasetText) {
var parsedCSV = d3.csv.parseRows(datasetText);
var sampleSVG2 = d3.select("#viz")
.append("svg")
.attr("width", 100)
.attr("height", 100);
sampleSVG2.selectall("circle")
.data(parsedCSV)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "blue")
This is probably not "correct" but it works. By calling a new svg area for each row and each circle it worked.
var sampleSVG = d3.select("#potato")
.data(parsedCSV)
.enter().append("circle")
.append("svg")
.attr("width", 100)
.attr("height", 100);
sampleSVG.append("circle")
.style("stroke", "gray")
.style("fill", "blue")
.attr("r", 40)
.attr("cx", 50)
.attr("cy", 50)
.on("mouseover", function(){d3.select(this).style("fill", "red");})
.on("mouseout", function(){d3.select(this).style("fill", "steelblue");});

Resources