score:3
/* * We need a different scale for drawing the y-axis. It needs * a reversed range, and a larger domain to accomodate negaive values. */
This is not necessary and creates more complication. A single scale is sufficient and will always match your data with your axis. As soon as you create different scales for the drawn axes and data, you'll find greater potential for conflict between the two.
Instead let's create one scale, yScale
here:
var yScale = d3.scaleLinear()
.domain([-100,100]) // min & max of input values
.range([chartHeight,0]) // mapped to the bottom and top of the plot area
For values under 0, negative bars, the top of the bar will be at yScale(0)
. The bottom of the rect will be at yScale(value)
. The difference between the two, the height, will be equal to yScale(value) - yScale(0)
.
For values over 0, the bottom of the bar will be at yScale(0)
, the top of the bar will be at yScale(value)
. To find the height we use yScale(0)-yScale(value)
.
Since the height is just the absolute difference between yScale(0)
and yScale(value)
we can just use Math.abs(yScale(0)-yScale(value))
to find the height of all rectangles.
I've remodelled your example code considering the above:
var data = [-76, -55, -51, -44, -35, 27];
var height = 250;
var width = 500;
var margin = {left: 50, right: 10, top: 20, bottom: 20};
var svg = d3.select("body").append("svg")
.attr('height', height)
.attr('width', width)
.style('border', '1px solid')
.append("g")
// apply the margins:
.attr("transform","translate("+[margin.left+","+margin.top]+")");
var barWidth = 30; // Width of the bars
// plot area is height - vertical margins.
var chartHeight = height-margin.top-margin.left;
// set the scale:
var yScale = d3.scaleLinear()
.domain([-100, 100])
.range([chartHeight, 0]);
// draw some rectangles:
svg
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", function(d, i) { return i * barWidth; })
.attr("y", function(d,i) {
if(d < 0) {
return yScale(0); // if the value is under zero, the top of the bar is at yScale(0);
}
else {
return yScale(d); // otherwise the rectangle' top is above yScale(0) at yScale(d);
}
})
.attr("height", function(d) {
// the height of the rectangle is the difference between the scale value and yScale(0);
return Math.abs(yScale(0) - yScale(d));
})
.attr("width", barWidth)
.style("fill", "grey")
.style("stroke", "black")
.style("stroke-width", "1px")
var yAxis = d3.axisLeft(yScale);
svg.append('g')
.call(yAxis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Additionally, we can simplify a bit further. The minimum of yScale(value)
and yScale(0)
(the value closer to the top of the SVG) will be the top of a the rectangle regardless of the value the rectangle represents.
var data = [-76, -55, -51, -44, -35, 27];
var height = 250;
var width = 500;
var margin = {left: 50, right: 10, top: 20, bottom: 20};
var svg = d3.select("body").append("svg")
.attr('height', height)
.attr('width', width)
.style('border', '1px solid')
.append("g")
// apply the margins:
.attr("transform","translate("+[margin.left+","+margin.top]+")");
var barWidth = 30; // Width of the bars
// plot area is height - vertical margins.
var chartHeight = height-margin.top-margin.left;
// set the scale:
var yScale = d3.scaleLinear()
.domain([-100, 100])
.range([chartHeight, 0]);
// draw some rectangles:
svg
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", function(d, i) { return i * barWidth; })
.attr("y", function(d,i) {
return Math.min(yScale(0),yScale(d))
})
.attr("height", function(d) {
// the height of the rectangle is the difference between the scale value and yScale(0);
return Math.abs(yScale(0) - yScale(d));
})
.attr("width", barWidth)
.style("fill", "grey")
.style("stroke", "black")
.style("stroke-width", "1px")
var yAxis = d3.axisLeft(yScale);
svg.append('g')
.call(yAxis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
By using the minimum of the two it gives us a bit more freedom: we could flip the graph by only changing the domain of the scale (if for some reason we wanted to represent negative values as though they were positive...)
Source: stackoverflow.com
Related Query
- D3.js V5 - Why is my bar chart axis not scaling?
- D3 bar chart axis not scaling correctly
- X axis not displaying on bar chart using d3.js
- D3.js bar chart - axis and labels not working / transitioning
- d3.js axis labels not displaying in responsive bar chart
- Why does my bar chart using scaleBand not line up with my tick marks?
- Why are the first two text labels of my bar chart not shown?
- X axis label not displayed in bar chart with scroll and zoom feature - d3js, Brushing
- dc.js Stacked Bar Chart having only one column and with elastic X Axis is not rendered properly
- How can I make a bar chart starting from the 0 point of the y axis and not from the bottom of the svg?
- Right Axis not displaying on Dual Axis Grouped Bar and Line Chart D3
- Why are my axes not positioning over my bar chart in this d3.js graph?
- D3 stacked bar chart not able to see full x axis lables
- D3.js bar chart not selecting or binding "date" data to Y axis label "text" elements on first ajax request
- Make simple bar chart using C3 with separate columns on the x axis
- Hide all text on y axis dc.js bar chart
- d3 bar chart y axis ticks and grid lines above max value
- Y axis label not displaying large numbers - Multi-Bar Chart
- DC.js bar chart with date axis
- Trouble using DC.js (crossfilter and d3 convenience library) - bar chart not showing values
- Need help lining up x axis ticks with bars in D3.js bar chart
- d3 bar chart using rangeRoundBands - why is there outer padding?
- dc.js bar chart with ordinal x axis scale doesn't render correctly
- How to modify axis labels in d3 for a stacked bar chart when the axis labels are mapped as part of the scale's domain
- D3 bar chart not showing first element in array
- x axis labels overlapping for grouped category bar chart in d3
- D3 radial bar chart adjust radius scaling
- Scaling D3 bar chart to container size
- d3.js Stacked bar chart with Logarithmic Scaling
- Stacked Bar Chart using d3.js stack layout; the bar sections not always in correct place
More Query from same tag
- D3 Targeting/Control Over Specific Arcs
- Line is not displayed correctly d3.js geo and google maps
- Color overlapped portions of multi line chart
- Hierarchial edge bundling in d3 is not working on my mac
- create values instead of random data in d3.js
- viewbox with pixel value to make d3 chart resposive is not working properly
- Can't make paths draw growing slowly with D3
- Stacked Area Chart in nvd3js - X Axis overflow
- Get constant interval of ticks value in d3.scaleTime()
- Array elements representation in data table
- d3js Smooth lines for linechart
- d3 mouse over event doesn't fire correctly if set from function(d)
- How to inform Angular directive that the scope values have changed?
- d3 handling mouse events in charts
- d3/html simple div tooltip location
- how to drag element with mouse move
- How to align legend dynamically on top-center of the chart in c3.js?
- Starting Transitions and Animations With Area Graph in D3.JS
- How to use d3.scaleLinear to find the radius of a map in d3
- X scale function in D3.js keeps returning undefined
- Resizing d3 / dagre-d3 svg to show all contents
- d3.select(this) is not selecting the rect
- How do I apply two svgs on one html page?
- Apache Tomcat and Spring MVC working with javascript library on a view
- How to maintain the SVG marker width and height ?
- Issue formatting data in JavaScript for a pie chart
- Error: Type 'number | undefined' is not assignable to type 'number | { valueOf(): number; }'?
- D3 function to parse the date not working
- d3.js transition is not working with property method
- D3.Js charts in excel