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.
Related
I am not being able to have the percentage display over the bar chart with the code:
chart3barchart2
.width(500)
.height(500)
.x(d3.scale.ordinal().domain(['18-21', '22-26', '27-30', '31-35']))
.xUnits(dc.units.ordinal)
.margins({top: 24, left: 0, right: 10, bottom: 20})
.colors(d3.scale.category10())
.brushOn(false)
.ordinalColors(['#FC6E4C'])
.dimension(ageDim)
.group(ageGroup)
.valueAccessor(function (d) { return parseInt((d.value.RespondCount/ntotal2.all()[0].value.RespondCount* 100).toFixed(0),10) + "%";})
.elasticY(true)
.yAxisPadding('60%')
.renderLabel(true)
.barPadding(0.2)
.outerPadding(0.6);
dc.renderAll("viz2");
See this fiddle for the whole code.
each time I put the "%" to .valueAccessor(function (d) { return parseInt((d.value.RespondCount/ntotal2.all()[0].value.RespondCount* 100).toFixed(0),10) + "%";}) the graph disappear altogether without showing an error in the browser console. Does someone has an idea ? thank you!
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;
});
I have a Composite Linechart
The .elasticX(true) does not work :/ Could Someone help me
var composite = dc.compositeChart("#durationline-chart");
composite.width(1500).height(350)
.group(Durations)
.brushOn(true)
.yAxisLabel("Duration")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.margins({ top: 10, left: 50, right: 10, bottom: 50 })
.elasticY(true)
.elasticX(true)
.renderlet(function(chart) {
chart.selectAll("g.x text")
.attr('transform', "rotate(+20)");
})
.compose([
dc.lineChart(composite)
.group(Testcase_Time, "Time")
.colors('#1E90FF'),
dc.lineChart(composite)
.group(Testcase_Smartkey, "Smartkey")
.colors('red')]);
EDIT: Here is the jsfiddle: https://jsfiddle.net/gordonwoodhull/o9xx3fmm/
I think you mean the elastic is not kicking in when the chart is filtered.
This is because crossfilter still returns bins if they are empty - they just have value zero. So dc.js still detects the domain of all the bins, including the empty ones.
What you can do is use a fake group to remove the empty bins
function remove_empty_bins(source_group) {
return {
all:function () {
return source_group.all().filter(function(d) {
return d.value != 0;
});
}
};
}
var filtered_group = remove_empty_bins(group);
chart.dimension(dim)
.group(filtered_group)
...
Then dc.js will detect only the domain of non zero values. More details in the FAQ.
You have to apply this to all groups that make up the chart.
I am trying to work with D3 transitions and an image and I seem to be having trouble.
I am trying to cause the image to disappear by having the top and bottom of the image close together until it gets to the middle, like a shutter effect, or erasing lines from the top and bottom until it is all gone. I don't want the image to scale at all, I just want it to close.
So far I have gotten the image to scale down to 0, but that is not what I want.
Also on the first transition it drops the image to the middle of the box before it starts the transition, whats up with that?
http://jsfiddle.net/Qda6B/
var svgContainer = d3.select("#box").append("svg")
.style("width", '100%')
.style("height", '100%')
.style("background-color","blue");
var imgs = svgContainer.append("svg:image")
.attr("xlink:href", "http://guiaavare.com/img/upload/images/Aishwarya-Rai-face.jpg")
.attr("width", "400")
.attr("height", "400");
d3.select("#inbutton").on("click", function () {
imgs
.attr("height",400)
.transition()
.attr({
height: 0,
y: 200
})
.duration(500);
});
d3.select("#outbutton").on("click", function () {
imgs
.transition()
.attr({
height: 400,
y: 0
})
.duration(500);
});
Thanks in advance
You can achieve the effect you are after using clipPath: http://jsfiddle.net/Qda6B/5/
var clipRect = svgContainer.append('svg:defs')
.append('svg:clipPath')
.attr('id', 'shutter-clip')
.append('rect')
.attr({
x: 0,
y: 0,
height: 400,
width: 400
})
var imgs = svgContainer.append("svg:image")
// ...
.attr("clip-path", "url(#shutter-clip)");
And then doing the transitions on the height of the rect inside the clipPath.
As an aside, though this is possible to do with d3, this very likely belongs in the domain of CSS3 transitions or jQuery or GASP animations.
I want to add a title text over the graph in NVD3.js.
I tried the following,
nv.addGraph(function() {
var chart = nv.models.linePlusBarWithFocusChart()
.margin({top: 30, right: 60, bottom: 50, left: 70})
.x(function(d,i) { return i })
.color(d3.scale.category10().range());
chart.append("text")
.attr("x", 200)
.attr("y", 100)
.attr("text-anchor", "middle")
.text("Sample Charts");
}
Its (Highlighted) working for D3.js but not working for NVD3.js. I'm getting a Blank page..
I want to place the text over the Chart as like the following image (Which is created in Paint)
How can I achieve this?
You can use D3 to select the container SVG and append the title:
d3.select('#chart svg')
.append("text")
.attr("x", 200)
.attr("y", 100)
.attr("text-anchor", "middle")
.text("Sample Charts");
This assumes that you're using the same ID etc for the SVG as in the NVD3 examples, if not, simply adjust the selector accordingly.
Taking a different approach, I wanted to have better control over the layout and style of the chart so instead of adding it as an text element inside the <svg> tag I added the title outside with help from jQuery.
var $svg = $('#chart svg');
$svg.parent().append('<div class="chart-title">Sample Charts</div>');
chart-title can be used to style the text element inside svg tags as well, but centering is much easier than having to use the width of the svg to set the x value like so:
svg.append('text')
.attr('x', width / 2)
.attr('y', 20)
.attr('text-anchor', 'middle')
.attr('class', 'chart-title')
.text('Sample Charts');
The above solution only works if you are setting the width. In my case the width was set to auto so until it created the chart it didn't have a width to refference. I actually modified the nvd3 code because I thought it was silly that some charts had titles and some didn't. There were 3 places I modified in each chart. Inside the margin section I added
var margin = {top: 30, right: 30, bottom: 30, left: 60}
, marginTop = null
.
.
.
, title = false
;
Inside the chart function I added
function chart(selection) {
.
.
.
if(title) {
g.append("text")
.attr("x", (availableWidth - margin.left)/ 2)
.attr("y", -4)
.attr("text-anchor", "middle")
.text(title);
}
Inside the chart options I added
chart._options = Object.create({}, {
// simple options, just get/set the necessary values
width: {get: function(){return width;}, set: function(_){width=_;}},
.
.
.
title: {get: function(){return title;}, set: function(_){title=_;}},
Then in your controller or where ever use
chart.title('Your chart Title');