NVD3 stacked bar chart x-axis label issue - d3.js

I wrote codes to plot stacked bar chart using NVD3.
Everything looks perfect untill we resize the window.
URL - https://jsfiddle.net/sujit77/45zg0yoe/2/
The issue is that the x-axis label moves up and merges along with axis ticks.
nv.addGraph(function() {
var chart = nv.models.multiBarChart()
.margin({top: 20, right: 20, bottom: 90, left: 50})
.stacked(true)
.reduceXTicks(false)
// .staggerLabels(true)
.color(d3.scale.category20().range())
.x(function(d){ return d.key })
.rotateLabels(-45)
.y(function(d){ return d.value })
chart.xAxis
.axisLabel('This is X Axix')
//.axisLabelDistance(80)
chart.yAxis
.axisLabel('This is Y Axix')
.axisLabelDistance(40)
.tickFormat(d3.format(",f"));
d3.select('#chart').append('svg')
.attr('width', 500)
.attr('height', 500)
.datum(chartData)
.call(chart)
d3.select(".nv-axislabel").attr("y", 76)
console.log(d3.select(".nv-axislabel").attr("y"))
nv.utils.windowResize(chart.update);
return chart;
});

Related

y axis ticks disappear in responsive chart in d3.js v4

I had perfectly adequate ticks in my earlier statically sized plot using d3.js v4; once I made it resizable, the ticks and values disappeared from the y axis.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test Plot Viewer</title>
<script src="js/lib/d3.v4.min.js"></script>
<script src="js/lib/jquery.min.js"></script>
<style>
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
#chart {
position: fixed;
left: 55px;
right: 15px;
top: 10px;
bottom: 55px;
}
</style>
</head>
<body>
<div id="chart"></div>
<script>
var chartDiv = document.getElementById("chart");
var svg = d3.select(chartDiv).append("svg");
// parse the date time
var parseTime = d3.timeParse("%m/%d %H:%M");
function render() {
$("svg").empty();
// Extract the width and height that was computed by CSS.
var width = chartDiv.clientWidth;
var height = chartDiv.clientHeight;
// Use the extracted size to set the size of an SVG element.
svg
.attr("width", width)
.attr("height", height);
var margin = {top: 10, right: 15, bottom: 55, left: 55};
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var line = d3.line()
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.solar); });
// Get the data
d3.csv("data_fred.csv", function(error, data) {
if (error) throw error;
// format the data
data.forEach(function(d) {
d.time = parseTime(d.time);
d.solar = +d.solar;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.time; }));
y.domain([0, d3.max(data, function(d) { return d.solar; })]);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", line);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%m/%d %H:%M ")));
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y))
.ticks(10);
});
}
render();
// Redraw based on the new size whenever the browser window is resized
window.addEventListener("resize", render);
</script>
</body>
</html>
The submitter function wants more details, but I have none...
blah
blah
blah
blah
characters added to pad non-code content.
The ticks are now gone on the y axis. I've added the .tick attribute to the y axis, but no joy.
How do I get my y axis ticks back on this responsive version of the chart? TIA
Posted later: Anyone? My non-responsive version of the code is drawing correctly; "responsifying" it makes the y-axis ticks and units disappear. I've tried almost every permutation of command ordering and placement, but no luck.
Whats happening here is your Y axis ticks are getting hidden because they're not in the viewport. What you need to do is put all the elements in your svg in a <g> wrapper and translate it by left and top margins.
Here's a fiddle
var chartDiv = document.getElementById("chart");
var svg = d3.select(chartDiv).append("svg");
var g = svg.append('g');
function render() {
$('svg').empty();
// Extract the width and height that was computed by CSS.
var width = $('#chart').width();
var height = $('#chart').height();
// Use the extracted size to set the size of an SVG element.
svg
.attr("width", width)
.attr("height", height);
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 50,
left: 40
};
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
// parse the date time
var parseTime = d3.timeParse("%m/%d %H:%M");
// set the ranges
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var valueline = d3.line()
.x(function(d) {
return x(d.time);
})
.y(function(d) {
return y(d.solar);
});
// Get the data
var data = [{
'time': '11/30 04:55',
'solar': -1.1
}, {
'time': '11/30 05:00',
'solar': -1.1
}, {
'time': '11/30 05:05',
'solar': -1.5
}, {
'time': '11/30 05:10',
'solar': -2
}, {
'time': '11/30 05:15',
'solar': 1
}]
// format the data
data.forEach(function(d) {
d.time = parseTime(d.time);
d.solar = +d.solar;
});
console.log(data)
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.time;
}));
var yExtent = d3.extent(data, function(d) {
return d.solar;
})
y.domain(yExtent);
g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Add the valueline path.
g.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
// Add the X Axis
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickFormat(d3.timeFormat("%m/%d %H:%M ")))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-45)");
// Add the Y Axis
g.append("g")
.call(d3.axisLeft(y));
}
// d3.select("svg").remove();
// svg.remove();
// d3.selectAll("g > *").remove()
// d3.selectAll("chartDiv.path.line").remove();
// d3.select("path.line").remove();
render();
// Redraw based on the new size whenever the browser window is resized.
window.addEventListener("resize", render);
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chart"></div>
Happy coding :)
Got it - the axis ticks were disappearing off the left edge of the window - fixed that with a transform/translate:
// Add the Y Axis
svg.append("g")
.attr("transform", "translate(40 ,10)")
.call(d3.axisLeft(y));
...with a similar translation of the x axis and path to match.
Also, the axis scale now appeared with an extent of 0 to 1.0, as it wasn't being passed out of the file read loop since it was an asynchronous operation. Bringing the svg.append's into the data read loop restored my "normal" units to the axis.

Circles on nvd3 line chart

I need to add circules/nodes to each point on a line chart of nvd3.
I have my codes here - https://jsfiddle.net/sujit77/7ns2g4a1/12/
Also I need to have these circles with different colors depending on value at that point.
I tried to follow "http://www.d3noob.org/2013/01/change-line-chart-into-scatter-plot.html". But messed up my code between D3 and nvd3 functions.
nv.addGraph(function() {
var chart = nv.models.lineChart()
.x(function(d) {
return d3.time.format("%Y-%m-%d %H:%M:%S").parse(d['key']);
})
.y(function(d){ return d.value; })
var format = d3.time.format("%m %d %Y");
chart.yAxis
.tickFormat(d3.format(',.2f'));
chart.xAxis
.tickFormat(function(d) {
return d3.time.format('%Y %b %d')(new Date(d))
});
d3.select('#line-charts').append('svg')
.attr('height', 250)
.attr('width', 400)
.datum(dataValue)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
I found similar question - Draw a circle at a point on an NVD3 line chart, but its unaswered yet.

Trouble with nvd3 date-data line chart

I am quite new in D3 and nvd3. I am trying to plot a graph with date axis and data axis - https://jsfiddle.net/sujit77/7ns2g4a1/6/.
var dataValue = [{'key':'Line', 'values':[{"key":"2016-04-04 0:0:0","value":1},{"key":"2016-04-05 0:0:0","value":1},{"key":"2016-04-07 0:0:0","value":1},{"key":"2016-04-08 0:0:0","value":1},{"key":"2016-04-11 0:0:0","value":1},{"key":"2016-04-13 0:0:0","value":1},{"key":"2016-04-14 0:0:0","value":0.5},{"key":"2016-04-19 0:0:0","value":1},{"key":"2016-04-20 0:0:0","value":1},{"key":"2016-04-22 0:0:0","value":1},{"key":"2016-04-25 0:0:0","value":1},{"key":"2016-04-26 0:0:0","value":1},{"key":"2016-04-27 0:0:0","value":1},{"key":"2016-04-28 0:0:0","value":1},{"key":"2016-04-29 0:0:0","value":1},{"key":"2016-05-03 0:0:0","value":1},{"key":"2016-05-04 0:0:0","value":0},{"key":"2016-05-06 0:0:0","value":1},{"key":"2016-05-09 0:0:0","value":1},{"key":"2016-05-10 0:0:0","value":1},{"key":"2016-05-11 0:0:0","value":1},{"key":"2016-05-12 0:0:0","value":1},{"key":"2016-05-13 0:0:0","value":1},{"key":"2016-05-16 0:0:0","value":1},{"key":"2016-05-17 0:0:0","value":1},{"key":"2016-05-19 0:0:0","value":1},{"key":"2016-05-24 0:0:0","value":0},{"key":"2016-05-25 0:0:0","value":0.5},{"key":"2016-05-26 0:0:0","value":1}]}];
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart()
//.showControls(false)
//.showMaxMin(false);
.x(function(d) {return d3.time.format("%Y-%m-%d %H:%M:%S").parse(d['key']);})
var format = d3.time.format("%m %d %Y");
chart.yAxis
.tickFormat(d3.format(',.2f'));
chart.xAxis
.tickFormat(function(d) { return d3.time.format('%Y %b %d')(new Date(d)) });
d3.select('#line-charts').append('svg')
.attr('height', 250)
.attr('width', 400)
.datum(dataValue)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
I am not able to plot the graph which should have been generated using the sample data. I am getting following error in browser's console window -
Error: attribute transform: Trailing garbage, "translate(0,NaN)".
Along with that I am trying to hide the bottom scale and min-max value in X-axis using ".showControls(false)" and ".showMaxMin(false)". But those are not working.
You forgot to do the y accessor.
Do something like:
chart.y(function (d) { return d.value; });

dc.js: Composite Chart filtering/labeling

I have the following composite chart made in dc.js:
barChart
.dimension(savingsDimension)
.colors('#009900')
.centerBar(true)
.elasticY(true)
.title(function(d) { return d.key + ": " + d.value; });
barChart2
.dimension(savingsDimension)
.colors('#000099')
.centerBar(true)
.elasticY(true)
.title(function(d) { return d.key + ": " + d.value; });
var lineChart = dc.lineChart(compositeChart)
.dimension(savingsDimension)
.colors('red')
.useRightYAxis(true)
.renderDataPoints({
radius: 3,
fillOpacity: 0.5,
strokeOpacity: 0.8
});
var xUnits = data.map(function (d) {return d.short_date; }).sort();
compositeChart
.width(1300)
.height(350)
.x(d3.scale.ordinal().domain(xUnits))
.xUnits(dc.units.ordinal)
.xAxisLabel('Month')
.brushOn(false)
.elasticY(true)
.margins({left: 80, top: 10, right: 190, bottom: 80})
.legend(dc.legend().x(1160).y(220).itemHeight(13).gap(5))
.compose([barChart, barChart2,
lineChart
]).renderlet(function(chart){
chart.selectAll("g.x text")
.attr('transform', "rotate(-65)")
.attr('x', -20);
});
barChart.group(fSavingsDimensionGroup, ' First Savings');
barChart2.group(sSavingsDimensionGroup, 'Second Savings');
The first thing I am having trouble with is making it so that I can select an x-range on this composite chart which will then filter all of my other charts. Right now, I can select certain bars and filter it that way, but I can't select a range like in this example: http://dc-js.github.io/dc.js/examples/filtering.html
I tried using .controlsUseVisibility(true) but it just errors out.
Also, even though I have .centerBar(true) on both my bar charts, the labels still aren't centered. Not sure what I am doing wrong there.
Edit #1:
Changed the code to:
compositeChart
.width(1300)
.height(350)
.x(d3.time.scale().domain([savingsDimension.bottom(1)
[0].billing_period_start, savingsDimension.top(1)
[0].billing_period_start]))
[0].billing_period_start, savingsDimension.top(1)
[0].billing_period_start))
.xAxisLabel('Month')
.elasticY(true)
.margins({left: 80, top: 10, right: 190, bottom: 80})
.legend(dc.legend().x(1160).y(220).itemHeight(13).gap(5))
.renderlet(function(chart){
chart.selectAll("g.x text")
.attr('transform', "rotate(-65)")
.attr('x', -36)
.attr('y', -20);
});
compositeChart.xAxis().tickFormat(d3.time.format('%m-%Y')).ticks(24);
compositeChart.xUnits(d3.time.months)
And the chart now looks like:
The bars are weirdly spaced out and I have no idea why.
I can now select a range on the chart, but it doesn't actually do any sort of filtering to the chart or any other chart on the page.
Currently the filtering behavior is selected by the type of x scale, so to get continuous brushing you could use a quantitative scale such as d3.time.scale(), convert your dates to date objects, and then use xAxis().tickFormat() to display them the way you want.
Here is the feature request to allow the range brush on ordinal charts. It is mainly a question of how to design the feature in a general way.
You are moving the tick labels with your renderlet, so you should adjust the displacement there in order to center your labels.

Chart gets clipped when setting height and width

I'm trying to create a simple line graph using nvd3.js. I got a simple one working which looks like so:
When I manually set my height and width, it all gets cut off.
My code looks like so:
var min_date = data[0].values[0].x
var max_date = data[0].values[0].x
var xScale = d3.time.scale()
.domain([min_date, max_date]);
var width = nv.utils.windowSize().width - 40,
height = nv.utils.windowSize().height - 40;
nv.addGraph(function() {
var chart = nv.models.lineChart()
.useInteractiveGuideline(true)
.height(height)
.width(width)
;
chart.xAxis
.scale(xScale)
.axisLabel('Day')
.tickFormat(function(d){
return d3.time.format('%x')(new Date(d))
})
.tickValues(data[0].values.map(function(d){
return d.x;
}))
;
chart.xScale(d3.time.scale());
chart.yAxis
.axisLabel('Followers')
.tickValues(data[0].values.map(function(d){
return d.y;
}))
.ticks(1)
;
d3.select('#chart svg')
.datum(data)
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
I can't seem to figure out what's going on. Any ideas?
Update
Here's a jsfiddle of the top graph, before I try to resize it. http://jsfiddle.net/yw7Jn/1/
Dates can be ignored. They got messed up when I made the fiddle but work fine for me.
If you change the dimensions for the chart, you also need to change the dimensions for the enclosing SVG accordingly:
var chart = nv.models.lineChart()
.useInteractiveGuideline(true)
.height(800)
// ...
d3.select('#chart svg')
.attr("height", 800)
.datum(chartData)
...
Complete demo here.

Resources