How to add background shading to D3 line chart - javascript

I would like to add shading to the background of a D3 line graph. There would be different shades for different parts of the line. Here is an example
My approach is the add rectangle svg to the chart, but that doesn't seem to be working because I don't know how to make the width correspond with the data.
here is a jsfiddle
Here is an example of the rectangle creation:
svg.append("rect")
.attr("class", "shading")
.attr("x", d[1].date)
.attr("y", 80)
.attr("width", 20)
.attr("height", 20)
.attr("fill", "blue");
Am I on the right track? How do I find the width so that it corresponds with the data?
UPDATE: There will be multiple square of different widths, so I can't just grab the width of the entire svg.

You can do it like this:
//get all the ticks in x axis
//make a pair of it refer: d3.pair
var data = d3.pairs(svg.selectAll(".x .tick").data());
//make a color category
var c10 = d3.scale.category10();
//to svg append rectangles
svg.selectAll("rect")
.data(data)//for the tick pair
.enter()
.append("rect")
.attr("class", "shading")
.attr("x", function(d){return x(d[0])})//x will be the 1st tick
.attr("y", 0)
.attr("width", function(d){return (x(d[1]) - x(d[0]));})//width will be the diff of 1st and 2nd tick
.attr("height", height)
.attr("opacity", 0.2)
.attr("fill", function(d,i){return c10(i)});//use color category to color the rects.
working code here

fill the svg first with the data, then after that get the width property, it should automatically calculate it

Related

D3 V4 triangle symbol usage

I am trying to use the triangle symbol for connected scatter plot using D3 v4,
but all the symbols are placed on the top of y-axis instead of given x and y values.
I have tried displaying only one symbol it works fine, but as a scatterplot, it is not working.
have tried with the circle and it works fine.
var svg = d3.select("svg")
.attr("width", 800)
.attr("height",800)
.append("g").attr("transform","translate(50,40)")
var arc = d3.symbol().type(d3.symbolTriangle);
svg.append('g').selectAll('valueline')
.data(tryo)
.enter()
.append('path')
.attr('d', arc)
.attr("x", function(d){ return x(d.xvalue) })
.attr("y", function(d){ return y(d.yvalue) })
.attr("width", 15)
.attr("height", 10);
I am expecting a scatter plot using the triangle symbol

How to do stroke-opacity:0 with d3

Here is my code. My target - do intervals between slices in pie chart.
chart.svg.selectAll('path')
.style('stroke-opacity','0.0')
.style('stroke-width','10');
I think if stroke opacity will be 0 on piechart slices on web page it will be similar to interval between slices.
Problem: if stroke opacity equals to zero that doesn't work. If equals to number from 0.1 to 1.0 - all works. But I have another color from background.
Please give a hand to beginner! Thanks for attention and have a nice day.
I believe the problem comes from the misconception that, when you set stroke-opacity to 0, the stroke will be transparent and reveal the background colour, and the fill of the element will end at the internal limits of the stroke. But, in fact, if you set the stroke-opacity to 0, you'll reveal the fill of the element (and the background colour, once the stroke goes inwards and outwards in the default stroke-alignment).
Look, for instance, at this example:
var svg = d3.select("body")
.append("svg")
.attr("width", 300)
.attr("height", 300);
var color = d3.scale.category10();
data = [10, 20];
var rects = svg.selectAll(".rect")
.data(data)
.enter()
.append("rect");
rects.attr("x", function(d){ return d*10})
.attr("y", 0)
.attr("width", 100)
.attr("height", 80)
.attr("fill", function(d){ return color(d)})
.attr("stroke-width", 10)
.attr("stroke", "white")
.attr("stroke-opacity", 0);
var rects2 = svg.selectAll(".rect2")
.data(data)
.enter()
.append("rect");
rects2.attr("x", function(d){ return d*10})
.attr("y", 100)
.attr("width", 100)
.attr("height", 80)
.attr("fill", function(d){ return color(d)})
.attr("stroke-width", 10)
.attr("stroke", "white");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
Both the pairs of rectangles are absolutely equal:
rects.attr("x", function(d){ return d*10})
.attr("y", 0)
.attr("width", 100)
.attr("height", 80)
.attr("fill", function(d){ return color(d)})
.attr("stroke-width", 10)
.attr("stroke", "white")
The only difference is that, in the upper pair, I add:
.attr("stroke-opacity", 0);
And that is the same of having no stroke.
You can see that, independent of the stroke alignment, the area and the size of the element is the same. Check the default stroke:
The rect element, outlined by a black line, remains the same.
To finish, I just found this fiddle (I don't know who's the author), and I set the stroke to white and stroke-width to 10: this is what you want, imitating a real padding. But you'll not get this result setting the stroke opacity to 0: https://jsfiddle.net/j1769sx2/

D3 chart like the US government analytics

I want to modify charts I have used in D3 to be like those on the US government analytics. I am unsure where to start. The JSfiddle below is where I am starting from.
Do I have to modify the chart to a stacked bar chart, a bullet chart or simply create the recs and add more space between them and position labels above the charts?
Has anyone done anything similar with D3?
My starting point: http://jsfiddle.net/Monduiz/drhdtsaq/
The Y axis, rects and labels:
[...]
var y = d3.scale.ordinal()
.domain(["Earnings", "Industry", "Housing", "Jobs"])
.rangeRoundBands([0, height], 0.2);
[...]
bar.append("rect")
.attr("width", 0)
.attr("height", barHeight - 1)
.attr("fill", "#9D489A")
.attr("width", function(d){return x(d.value);});
bar.append("text")
.attr("class", "text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.value; })
.attr("fill", "white")
.attr("font-family", "sans-serif")
.attr("font-size", "14px")
.attr("text-anchor", "end");
This is what I want to do:
EDIT
I have made some progress. Updated fiddle: http://jsfiddle.net/Monduiz/drhdtsaq/33/
Now I need to find how to move the ordinal categories between the bars.
Well, I got close enough after some attempts. I can polish things up with CSS.
updated fiddle: http://jsfiddle.net/Monduiz/drhdtsaq/66/
Basically, the solution is to create another set of rectangles called first using a second set of data to full value of the scale used. Then its just a matter of adjusting the size of the bars and positioning the labels.
bar2.append("rect")
.attr("height", y.rangeBand()-15)
.attr("fill", "#EDEDED")
.attr("width", function(d){return x(d);});
bar.append("rect")
.attr("height", y.rangeBand()-15)
.attr("fill", "#FFB340")
.attr("width", function(d){return x(d.value);});

Draw SVG image on paths but as big as needed

So I would like to show an image on a path. The pathes are created via topojson coordinates. The points are on the right position on my map. So the next thing is to show a SVG image on that point.
I tried that with appending svg:image, but no chance. I also tried to bring it into the path with the same result. I nowhere can see that image. Here an example with an PNG image. Because at least that should work to exclude SVG issues:
var featureCollection = topojson.feature(currentMap, currentMap.objects.points);
svgmap.append("path")
.attr("id", "points")
.selectAll("path")
.data(featureCollection.features)
.enter().append("path")
.attr("d", path);
svgmap.append("svg:image")
.attr("class","svgimage")
.attr("xlink:href", "pics/point.jpg" )
.attr("x", -20)
.attr("y", -20)
.attr("width", 13)
.attr("height", 13);
Edit
svgimage.append("pattern")
.attr("id","p1")
.attr("patternUnits","userSpaceOnUse")
.attr("width","32")
.attr("height","32")
.append("image")
.attr("xlink:href", "pics/point.jpg" )
.attr("width", 10)
.attr("height", 10);
svgmap.append("g")
.attr("id", "points")
.selectAll("path")
.data(featureCollection.features)
.enter().append("path")
.attr("d", path)
.attr("fill", "url(#p1)");
But still not working.
Edit2
I mentioned that it is an issue with the size. So I now played a bit with the sizes and there I can see some more, but most of them are not fully imaged. Just some pieces of the cirle somehow. Strange thing. I keep on testing:
svgimage.append("pattern")
.attr("id","p1")
.attr("patternUnits","userSpaceOnUse")
.attr("width","10")
.attr("height","10")
.append("image")
.attr("xlink:href", "pics/point.jpg" )
.attr("width", 15)
.attr("height", 15);
Here a picture of the current result (jpg): http://i.imgur.com/T58DA1j.png not yet perfect.
This is when I increase the pointRadius (this is now a SVG): http://i.imgur.com/Z7nZUWk.png
The solution is pretty easy. The size of the picture was just not correctly set. Also the userSpaceOnUse needs to be deleted and if needed you can set the creation position with x and y:
svgimage.append("pattern")
.attr("id","p1")
.attr("width","10")
.attr("height","10")
.append("image")
.attr("xlink:href", "pics/point.jpg" )
.attr("width", 5)
.attr("height", 5)
.attr("x", 1)
.attr("y", 2);
and in the second part it is important to set the pointRadius. You can set it directly on the path or in the definition. If you want to use different sizes later on it makes more sense to set it in the path directly:
.attr("d", path.pointRadius(3.5))

d3 enter/append/exit/remove sequence only appending

A set of rectangles is drawn initially with the following enter/append/exit/remove sequence, no problem. When I pass different data (meant to replace the existing data entirely) the new rectangles are drawn on top of the existing rectangles.
I am selecting "lgnds" instead of rect, because I have drawn other rectangles that I don't wish to disturb.
var svg = d3.select("#graph").append("svg")
elements = svg
.selectAll("lgnds")
.data(data, function(d){return d;});
elements
.enter()
.append("rect")
.attr("width", 15)
.attr("height", rectHeight)
.attr("x", 5)
.attr("y", function (d,i){return ((i*rectHeight)+(gap*(i+1)));})
.style("fill", function(d){ return d.color;});
elements
.exit()
.remove();

Categories