D3 Plotting Rectangles from Coordinate data - d3.js

I have rectangles that I would like to plot from a csv file in the following format:
x1,x2,y1,y2,color
2,4,5,8,blue
4,7,9,11,red
...
So basically, I have the endpoints for each rectangle, however conventional D3 appends rects using x, y, height and width -- all of which are needed I believe. x1, x2, y1, y2 don't apply to rects if I'm not mistaken. So I'm a little confused about which approach to take.
I originally thought a line or path could do the trick, but I do not think I can create distinct shapes and distinct fills this way, as they would all be drawn in one fell swoop.
Please advise as to which methods would be most suitable for this data type.

Since width is just x2 - x1 and height is just y2 - y1:
rectangleSelection.attr("x", function(d) {
return d.x1
})
.attr("y", function(d) {
return d.y1
})
.attr("width", function(d) {
return d.x2 - d.x1
})
.attr("height", function(d) {
return d.y2 - d.y1
})
.attr("fill", function(d) {
return d.color
})
Here is a demo (I'm using a <pre> element to simulate your CSV, and also I'm increasing your values for better see the rectangles):
var svg = d3.select("svg");
var data = d3.csvParse(d3.select("#csv").text())
var rects = svg.selectAll("foo")
.data(data)
.enter()
.append("rect");
rects.attr("x", function(d) {
return d.x1
})
.attr("y", function(d) {
return d.y1
})
.attr("width", function(d) {
return d.x2 - d.x1
})
.attr("height", function(d) {
return d.y2 - d.y1
})
.attr("fill", function(d) {
return d.color
})
pre{
display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">x1,x2,y1,y2,color
20,40,50,80,blue
40,70,90,110,red
70,130,60,80,green</pre>
<svg></svg>
Have in mind that you have to be sure that y2 is greater than y1 and x2 is greater than x1. Otherwise you'll get an error: A negative value is not valid.

Related

in d3js bar chart i want to have fixed bar width

http://bl.ocks.org/d3noob/8952219
I want to have bar size width to be fixed..
from above example i have changed the code from
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
to
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.date); })
.attr("width", 50)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
but the labels are not moving to proper place also bars are getting overlapped
You have to change the range() of your x scale, to fit with your bar width value:
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
to (if you want 50px as bar width)
var x = d3.scale.ordinal().range([0, data.length * 50]);
The range() method is used to define the display space for your scale.
I was looking for a similar solution. What #JulCh gave as an answer did not work out of the box for me, but lead me in the right direction.
Try:
var x = d3.scale.ordinal()
.range(d3.range(data.length).map(function (d) { return d * 50; }));
Where the inner d3.range creates an array containing the number of elements determined by data.length or some constant number (the number of bars you would like displayed).
Example: If data.length or some constant is 8 then [0,1,2,3,4,5,6,7] is returned from d3.range(8)
The map function then multiplies your fixed width of 50 against each element in the array returning [0,50,100,150,200,250,300,350].
D3 will then use these exact values to place your bars.

Stacked bar going right to left instead of left to right

I'm trying to create a simple single stacked bar chart that goes left to right.
I've adapted the code found here, and I've gotten pretty close.
However, the stacked data is in the wrong direction.
The data at index 0 is all the right to the right, and the data at index 2 is all the way to the left.
I have a feeling it's got something to do with the rectangle and transition, but I'm not sure where I went wrong.
var rect = layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter().append("rect")
.attr("y", function(d) {
return y(d.y);
})
.attr("x", 0)
.attr("height", y.rangeBand())
.attr("width", 0);
rect.transition()
.delay(function(d, i) {
return i * 10;
})
.attr("x", function(d) {
return x(d.x0 + d.x);
})
.attr("width", function(d) {
return x(d.x0) - x(d.x0 + d.x);
});
Fiddle
The main reason your stack starts at the right is that the range of your scale [width, 0] is inversely correlated to your domain [0, xStackMax]. Smaller input values will thus lead to larger output values, so your first x/x0 values will end up with values at the 'width' end of the scale.
Fix this so they both go in the same direction.
var x = d3.scale.linear()
.domain([0, xStackMax])
.range([0, width]);
Then change the x and width .attr calcs, the rects start at their scaled x0 coord and are as wide as the difference between x(d.x0 + d.x) - x(d.x0). For linear scales this can be simplified to x(d.x)
.attr("x", function(d) {
return x(d.x0);
})
.attr("width", function(d) {
return x(d.x0 + d.x) - x(d.x0);
});
https://jsfiddle.net/zkbxeby8/14/

Create rectangle instead of bubbles in d3js

I used this http://bl.ocks.org/mbostock/4063269 to create circles, but i would need to create rectangle instead of circle and all those rectangles needs to packed inside one bigger rectangle. please help.
This is how you can make rectangles instead of circles.
node.append("rect")
.attr("width", function(d) { return d.r*2; })//width is the diameter
.attr("x", function(d) { return d.r*-1; })
.attr("y", function(d) { return d.r*-1; })
.attr("height", function(d) { return d.r*2; })//height is the diameter
.style("fill", function(d) { return color(d.packageName); });
Now to create a rectangle which packs all of them
//get all the data
var data = d3.selectAll("g")[0].map(function(d) {
return d3.select(d).data()[0]
})
//get the min x max x min y max y
var xmin = d3.min(data, function(d){return d.x-d.r})
var xmax = d3.max(data, function(d){return d.x+d.r})
var ymin = d3.min(data, function(d){return d.y-d.r})
var ymax = d3.max(data, function(d){return d.y+d.r})
//make a rectangle to make it over other rectangles.
svg.insert("rect" ,":first-child")
.attr("x", xmin)
.attr("y", ymin)
.attr("height", ymax-ymin)
.attr("width", xmax-xmin)
.style("opacity", 0.3)
.style("fill","blue");
working example here

What is the correct way to draw lines direction by conditional

I have 3 datas with me. each data has different values. using the data size I am drawing lines.
my request is, how do I add the condition each of the values to draw the line different way?
for example my case, the second data need to draw from right to left, instead of left to right.
What is the correct way to do this?
var height = 500;
var width = 500;
var data = [
{"name":"name1", "size":10, "count":8},
{"name":"name2", "size":20, "count":20},
{"name":"name3", "size":30, "count":60}
]
var svg = d3.select('body').append('svg').attr({
width:width,
height:height
}).append('g');
var line = svg.selectAll('line')
.data( data )
.enter()
.append('line')
.style("stroke", "black")
.attr("x1", function(d){ 10 })
.attr("y1", function(d){ return d.size })
.attr('x2', function(d) { return 0 })
.attr("y2", function (d){ return d.size })
.transition()
.delay(2000)
.duration(2000)
.attr("x2", function (d){ return width - d.size })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Just insert a check in your drawing function.
function(d){
if(d.name === "name2")
// code to draw right to left
else
// code to draw left to right
}
or, if you prefer to use the index,
function(d, i){
if(i === 1)
// code to draw right to left
else
// code to draw left to right
}
If your logic affects x1, x2, y1, and y2, then it might be easier to do everything in a .each call:
var line = svg.selectAll('line')
.data( data )
.enter()
.append('line')
.style("stroke", "black")
.each(function(d, i){
// custom logic here to decide what's x1, x2, y1, y2
// based on d and i
d3.select(this){
.attr("x1", ...)
.attr("y1", ...)
.attr('x2', ...)
.attr("y2", ...)
// etc
});

How to update a Bar Chart in D3.js

I want to update my bar chart when the value of the chart get changes.
I get data for the chart from restful services.
I don't want to delete an entire chart and then redraw; instead I wanted to update the existing bar values with the new values.
1.Each and Every time the number of rows is getting changed when i get input from webservice for dataset.
2.I Can manage to update the bars height value when the number of rows is equal.But it contain more number of rows than before i have the problem facing unexpected output.
I submitted the sample code.//i just use this code from stack overflow site.
function mf(){
data = d3.range(10).map(next);
var rect= chart.selectAll("rect")
.data(data)
.attr("x", function(d, i) { return x(i) - .5; })
.attr("y", function(d) { return h - y(d.value) - .5; })
.attr("width", w)
.attr("height", function(d) { return y(d.value); });
rect.enter()
.append("svg:rect")
.attr("x", function(d, i) { return x(i) - .5; })
.attr("y", function(d) { return h - y(d.value) - .5; })
.attr("width", w)
.attr("height", function(d) { return y(d.value); });
rect.exit().remove();
}

Resources