Reputation: 59
I'm trying to learn SVG graphs, I've nearly completed my graph however I currently have overlapping bars, I believe this is due to a combination of my x axis return data and my json data. My x axis lists the months from my JSON data, but my JSON data can have multiple entries from the same month. and if this is the case then my entries will overlap for that month. What I need to do is return the month + day seperately, however I haven't been able to figure out how just yet.
JSON data example where there's 2 entries for the same month:
1: {dayNo: 2, monthNo: 7, monthName: "July", year: 2018, recordDate: "2018-07-02T00:00:00",…}
avgVolume: 3585.53
dayNo: 2
monthName: "July"
monthNo: 7
recordDate: "2018-07-02T00:00:00"
volumeLastYear: 4109.47
volumeToday: 3575.34
year: 2018
2: {dayNo: 30, monthNo: 7, monthName: "July", year: 2018, recordDate: "2018-07-30T00:00:00",…}
avgVolume: 3291.55
dayNo: 30
monthName: "July"
monthNo: 7
recordDate: "2018-07-30T00:00:00"
volumeLastYear: 3996.31
volumeToday: 3414.44
year: 2018
And here is the svg code:
$request.done(function (response) {
// remove old svg
$('svg').remove();
// create svg element
var $svg = d3.select('.card.mb-3.clickable-card.highlight')
.append('svg')
.attr('width', '100%')
.attr('height', '400px')
.attr('style', 'background-color: lavender')
.classed('svg display-svg', true);
// 2 determine size of svg element
var w = $svg.node().getBoundingClientRect().width;
var h = $svg.node().getBoundingClientRect().height;
// 10 chart margins
var chartMargin = new Object();
chartMargin.left = 40;
chartMargin.right = 25;
chartMargin.top = 25;
chartMargin.bottom = 40;
// 10 cont
h = h - chartMargin.bottom - chartMargin.top;
// Max volume
var maxVolume = d3.max(response, d => d.avgVolume);
// bar Margins / width
var barMargin = 10;
var barWidth = (w - chartMargin.left - chartMargin.right) / response.length;
// yScale
var yScale = d3.scaleLinear()
.domain([0, maxVolume])
.range([h, chartMargin.top]);
// xScale
var xScale = d3.scaleBand()
.domain(response.map(function (d) { return d.monthName; }))
.range([0, w - chartMargin.left - chartMargin.right])
.paddingInner(0.15);
// chartGroup
var chartGroup = $svg.append('g')
.classed('chartGroup', true)
.attr('transform', 'translate(' + chartMargin.left + ',' + chartMargin.top + ')');
// 5
var barGroups = chartGroup
.selectAll('g')
.data(response);
// 6
var newBarGroups = barGroups.enter()
.append('g')
.attr('transform', function (d, i) {
return 'translate('
+ (xScale(d.monthName))
+ ','
+ (yScale(d.avgVolume))
+ ')';
})
// yAxis label
var yAxis = d3.axisLeft(yScale);
chartGroup.append('g')
.classed('axis y', true)
.attr('transform', 'translate(' + -20 + ', ' + h / 2 + ')')
.append('text')
.attr('transform', 'rotate(-90)')
.attr('dx', '-0.8em')
.attr('dy', '0.25em')
.attr("text-anchor", 'middle')
.text("Reservoir Volume (ML)");
// xAxis label
var xAxis = d3.axisBottom(xScale);
chartGroup.append('g')
.attr('transform', 'translate(0,' + h + ')')
.classed('axis x', true)
.call(xAxis);
newBarGroups
.append('rect')
.attr('x', 0)
.attr('height', function (d, i) {
return h - yScale(d.avgVolume);
})
// animation
.style('fill', 'transparent')
.transition().duration(function (d, i) { return i * 500; })
.delay(function (d, i) { return i + 200; })
.attr('width', barWidth - barMargin)
.style('fill', function (d, index) {
return "hsl(240, 100%, " + (d.avgVolume / maxVolume * 80) + "%)"
});
// bar text
newBarGroups
.append('text')
.attr('transform', 'rotate(-45)')
.attr('text-anchor', 'middle')
.attr('x', function () { return 0; })
.attr('y', 50)
.attr('fill', 'white')
.text(function (d, i) { return d.avgVolume; })
.style('font-size', '1em')
});
in the xScale, I have tried changing the return data from
return d.monthName
to
return d.monthName + ' ' + d.dayNo
But then all my bars overlap and I get this error for each g element: d3.js:1211 Error: attribute transform: Expected number, "translate(undefined,25.183…".
Here is what I have currently with returning d.monthName:
Here is d.monthName + ' ' + d.dayNo:
Upvotes: 0
Views: 178
Reputation: 59
Nevermind sorry, I fixed it
I needed to change
var newBarGroups = barGroups.enter()
.append('g')
.attr('transform', function (d, i) {
return 'translate('
+ (xScale(d.monthName))
+ ','
+ (yScale(d.avgVolume))
+ ')';
})
to
var newBarGroups = barGroups.enter()
.append('g')
.attr('transform', function (d, i) {
return 'translate('
+ (xScale(d.monthName + ' ' + d.dayNo))
+ ','
+ (yScale(d.avgVolume))
+ ')';
})
Upvotes: 0