The maximum column width in the histogram

I'm looking for a way to limit the width of a column in a chart, I'm sure it should be relatively easy, but I can’t find a way to do this.

I fill out a chart from some dynamic data, where the number of columns can vary quite dramatically - from 1 to 20.

for example: csv sample

Location,Col1 "Your house",20 Location,Col1,Col2,Col3,Col4,Col5 "My House",12,5,23,1,5 

This works fine, and the column width is dynamic, however, when there is only one column in the data, I end up with one bar 756 wide (the whole chart) and I don’t like how it looks.

What I would like to do is always have a maximum column 100 pixels wide, regardless of the number of data columns.

Below is my script for the chart

Thank you very much,

 <script> var margin = { top : 40, right : 80, bottom : 80, left : 40 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.scale.linear().range([ 0, width ]); var y = d3.scale.linear().range([ height, 0 ]); var x0 = d3.scale.ordinal() .rangeRoundBands([0, width], .05); var x1 = d3.scale.ordinal(); var y = d3.scale.linear() .range([height, 0]); var chart = d3.select("body").append("svg") .attr("class","chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var legendChart = d3.select("body").append("svg") .attr("class","chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.csv("/sampledata.csv.txt", function(error, data) { // Use the first row of csv for header names var reasonNames = d3.keys(data[0]).filter(function(key) { return key !== "Location"; }); //console.log(reasonNames); data.forEach(function(d) { d.reasons = reasonNames.map(function(name) { return { name : name, value : +d[name] }; }); //console.log(d.reasons); }); x0.domain(data.map(function(d) {return d.Location; })); x1.domain(reasonNames).rangeRoundBands([0, x0.rangeBand()]); console.log(x0.rangeBand()); y.domain([0, d3.max(data, function(d) { return d3.max(d.reasons, function(d) { return d.value; }); })]); var maxVal = d3.max(data, function(d) { return d3.max(d.reasons, function(d) { return d.value; }); }); //console.log(maxVal); var xAxis = d3.svg.axis() .scale(x0) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left") //.tickFormat(d3.format(".2s")); chart.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); chart.append("g") .attr("class", "y axis") .call(yAxis); var location = chart.selectAll(".name") .data(data) .enter().append("g") .attr("class", "g") .attr("transform", function(d) { return "translate(" + x0(d.Location) + ",0)"; }); location.selectAll("rect") .data(function(d) { return d.reasons; }) .enter().append("rect") .attr("width", x1.rangeBand()-2) .attr("x", function(d) { return x1(d.name); }) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .style("fill", function(d,i) { return "#"+3+"9"+i; /*color(d.name);*/ }); chart.selectAll("text") .data(data) .enter().append("text") .attr("x", function(d) { return x1(d.name)+ x.rangeBand() / 2; }) .attr("y", function(d) { return y(d.value); }) .attr("dx", -3) // padding-right .attr("dy", ".35em") // vertical-align: middle .attr("text-anchor", "end") // text-align: right .text("String"); var legend = legendChart.selectAll(".legend") .data(reasonNames.slice().reverse()) .enter() .append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") //.attr("x", width - 18) .attr("x", 18) .attr("width", 18) .attr("height", 18) .style("fill", function(d, i) {/*console.log(i);*/return "#" + 3 + "9" + i; }); legend.append("text") //.attr("x", width - 24) .attr("x", 48) .attr("y", 9).attr("dy",".35em") //.style("text-anchor", "end") //.text(function(d,i) { return String.fromCharCode((65+i))+i; }); .text(function(d) { return d; }); }); </script> 
+6
source share
5 answers

The easiest way to achieve this is to change the line

 .attr("width", x1.rangeBand()-2) 

to

 .attr("width", Math.min(x1.rangeBand()-2, 100)) 

You can also adjust the starting position and / or addition.

+6
source

Code for setting the starting position if someone is stuck on it:

 .attr("x", function(d, i) { return x1(d.seriesName) + (x1.rangeBand() - 100)/2 ;}) 

PS: answer from Lars.

+4
source

Setting the absolute maximum width for columns does not allow rendering for different screen resolutions, div sizes, etc.

In my case, I just wanted the columns to not look so large when the number of columns is small in itself.It was easier and more straightforward to play with the definition of the scale by changing the maximum width (where all the columns fit), their inner and outer linings.

 var w = 600 // var w = parseInt(d3.select(parentID).style('width'), 10) // retrieve the div width dynamically var inner_padding = 0.1 var outer_padding = 0.8 var xScale = d3.scale.ordinal().rangeRoundBands([0, w], inner_padding, outer_padding) 

When rendering the graph, I simply ran the switch / if-else statement, which assigns different padding values. The smaller the number of columns for plotting, the more the values ​​of external_parting (and, ultimately, internal filling) I use.

This way I keep the graphics responsive .

+1
source

I can change the bandwidth using the answer above. But, unfortunately, my X Axis labels are not aligned when there is one bar on the chart and it uses the maximum width.

 var tradeGroup = svg.selectAll("g.trade") .data(trades) .enter() .append("svg:g") .attr("class", "trade") .style("fill", function (d, i) { return self.color(self.color.domain()[i]); }) .style("stroke", function (d, i) { return d3.rgb(self.color(self.color.domain()[i])).darker(); }); var aWidth = Math.min.apply(null, [x.rangeBand(), 100]); // Add a rect for each date. var rect = tradeGroup.selectAll("rect") .data(Object) .enter() .append("svg:rect") .attr("x", function (d) { return x(dx); }) .attr("y", function (d) { return y( (dy || 0) + (d.y0 || 0)); }) .attr("height", function (d) { return y(d.y0 || 0) - y((dy || 0) + (d.y0 || 0)); }) .attr("width", Math.min.apply(null, [x.rangeBand(), 100])); 
0
source

For completeness, the full answer would look like this:

 svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", (d) -> x1(d.name) + (x1.rangeBand() - d3.min([x1.rangeBand(), 100]))/2) .attr("width", d3.min([x1.rangeBand(), 100])) .attr("y", (d) -> y(d.grade) ) .attr("height", (d)-> height - y(d.value) ) 

(coffeescript syntax)

Please note that this is the complete answer, setting "width" and "x". In addition, the β€œx” setting takes into account when 100 width is not the minimum value.

0
source

All Articles