I have a data like this
Sl.No,Sex,Age_band,TYPE of Mesh,Type of Surgery
16,M,0-25,PHS,UL Inguinal
20,M,0-25,PHS,UL Inguinal
90,M,0-25,UHSL,UL Inguinal
95,M,0-25,UHSL,UL Inguinal
117,M,0-25,UHSL,UL Inguinal
119,M,0-25,UHSL,UL Inguinal
32,M,0-25,Ultrapro,Incisional
14,M,26-35,PHS,UL Inguinal
18,M,26-35,PHS,UL Inguinal
I am trying to plot a composite chart
and my code is
var mFilteredData = crossfilter(mData);
var mDimension = mFilteredData.dimension(dc.pluck("Age_band"));
var mGroup = mDimension.group().reduceCount(dc.pluck("TYPE of Mesh"));
var mGroup1 = mDimension.group().reduceCount(dc.pluck("Type of Surgery"));
var chart = dc.compositeChart(".chart");
chart
.width(400)
.height(300)
.yAxisLabel("User Count")
.renderHorizontalGridLines(true)
.dimension(mDimension)
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.compose([
dc.barChart(chart)
.centerBar(true)
.gap(100)
.colors('red')
.group(mGroup)
,
dc.barChart(chart)
.centerBar(true)
.gap(100)
.colors('blue')
.group(mGroup1)])
.brushOn(false)
.render();
But I am getting this errror
Uncaught TypeError: Cannot call method 'all' of undefined
I also had the same issue. After some digging around in the dc source code I saw that if you have an ordinal x scale, the chart calls it's groups all() function (not completely sure why, but it seems to be using the data for the x axis domain). By adding a group to your composite chart you will solve this issue. Like so:
dc.compositeChart(".chart")
.width(400)
.height(300)
.yAxisLabel("User Count")
.renderHorizontalGridLines(true)
.dimension(mDimension)
.group(mGroup)
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
Related
I have a barchart set-up as follows:
function makeGraphs(recordsJson, factorText) {
// Clean data
var records = jQuery.parseJSON(recordsJson);
let parseDate = d3.timeParse("%Y-%m-%d");
records.forEach(function(d) {
d.date = parseDate(d.date);
d.factor = d.factor == true ? 1 : 0;
});
// Create a Crossfilter instance
var ndx = crossfilter(records);
// Define Dimensions
var dateDim = ndx.dimension(d => d.date);
// Group Data
var dateGroup = dateDim.group();
var factorGroup = dateDim.group().reduceSum(dc.pluck('factor'));
var all = ndx.groupAll();
// Define values (to be used in charts)
var minDate = dateDim.bottom(1)[0]["date"];
var maxDate = dateDim.top(1)[0]["date"];
// Chart
const timeChart = new dc.CompositeChart("#time_chart");
timeChart
.height(300)
.x(d3.scaleTime().domain([minDate,maxDate]))
.yAxisLabel("Number of Lines")
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.compose([
new dc.LineChart(timeChart)
.dimension(dateDim)
.colors('blue')
.group(dateGroup, "Total")
.curve(d3.curveLinear),
new dc.BarChart(timeChart)
.dimension(dateDim)
.colors('red')
.centerBar(true)
.gap(1)
.alwaysUseRounding(true)
.group(factorGroup, factorText)
.xUnits(d3.timeDays)
])
.brushOn(false)
.render();
The barchart is always displayed with pencil-thin columns, representing correctly the count of 'factor' items in that date. This occurs no matter the size of day range I apply.
I have tried .xUnits(d3.timeWeeks) to see if it can be made to display better, to no avail (actually, it still displays daily totals, suggesting I need to construct an aggregate function). However, I really need daily counts.
As advised by Gordon, a CompositeChart needs to have its .xUnit property defined in the main chart section, not under one of its sub-chart types:
timeChart
.height(300)
.x(d3.scaleTime().domain([minDate,maxDate]))
.yAxisLabel("Number of Lines")
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.xUnits(d3.timeDays)
.compose([
new dc.LineChart(timeChart)
.dimension(dateDim)
.colors('blue')
.group(dateGroup, "Total")
.curve(d3.curveLinear),
new dc.BarChart(timeChart)
.dimension(dateDim)
.colors('red')
.centerBar(true)
.gap(1)
.alwaysUseRounding(true)
.group(factorGroup, factorText)
])
.brushOn(false)
.render();
The bar-chart component then displays with a proper width.
I'm trying to recreate the single select bar on a dc.js composite chart as shown here
https://dc-js.github.io/dc.js/examples/bar-single-select.html
I've tried adding a filter handler to the child chart but it never gets called when I click on the bar. I've also tried adding a filter handler to the Composite chart itself with no luck. Is there any way I can select a bar on a composite chart or do I have to assign it a colour and then color the other bars grey manually and redraw the graph based on what was clicked?
This is the initialization of the graph in my component.
The data goes through a formatting process where I parse the date using the formatData function. I also pass in a dimensions prop (apologies for the bad naming) which tells the component what kind of chart should correspond to the chart name and the color of the dataset.
dimensions={
{"Data1": ["line", AppStyles.color.warning],
"Data2": ["line", AppStyles.color.danger],
"Data3": ["bar", AppStyles.color.blue]
}
}
formatData = (data) => {
let formattedData = [];
for(let key in data) {
formattedData.push({
...data[key],
x: this.parseDate.parse(data[key].x)
})
}
return formattedData;
}
componentDidMount(){
let data = this.formatData(this.props.data);
this.ndx = crossfilter.crossfilter(data);
this.chart = dc.compositeChart(this.multiLineChartContainer);
this.dimension = this.ndx.dimension((d) => {
return d.x;
});
let minDate = this.dimension.bottom(1)[0].x;
let maxDate = this.dimension.top(1)[0].x;
let composeGroup = [];
Object.keys(this.props.dimensions).map((dim,i) => {
let grp = this.dimension.group().reduceSum((d) => {
return d[dim];
});
if(this.props.dimensions[dim][0] === "bar"){
composeGroup.push(dc.barChart(this.multiLineChartContainer)
.group(grp, dim)
.colors("blue")
.centerBar(true)
.addFilterHandler(function(filters, filter) {return [filter];})
)
} else {
composeGroup.push(dc.lineChart(this.multiLineChartContainer)
.group(grp, dim)
.colors(this.props.dimensions[dim][1])
.useRightYAxis(true)
);
}
});
this.chart.width(this.props.width)
.height(this.props.height)
.renderHorizontalGridLines(true)
.x(d3.time.scale().domain([minDate, maxDate]))
.elasticY(true)
.elasticX(true)
.xAxisLabel("Cohort")
.brushOn(false)
.yAxisLabel("Left")
.rightYAxisLabel("Right")
.xUnits(()=>{
return 30;
})
.legend(dc.legend().x(this.chart.width()- 130))
.compose(composeGroup)
this.chart.renderlet((chart) => {
chart.selectAll('circle, rect.bar').on("click", (event) => {
this.props.dataSelect(event);
});
});
this.chart.xAxis().ticks(5)
this.chart.render();
}
Please consider adding your code (or better, a running example) next time you ask a question on SO.
It would also help to spell out what "no luck" means - wrong click behavior? No chart displayed at all?
It's hard to guess what might be going wrong for you.
This works fine for me, although ordinal scales are a little bit tricky, and composing them in a composite chart even more so.
Is the problem that you were not using an ordinal scale? Because currently the kind of selection (brush or click) is determined by the scale/xUnits and it's hard to get around it.
composite
.width(768)
.height(480)
.x(d3.scaleOrdinal().domain(d3.range(1,21)))
.xUnits(dc.units.ordinal)
.yAxisLabel("The Y Axis")
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.brushOn(true)
.renderHorizontalGridLines(true)
.compose([
dc.barChart(composite)
.dimension(dim)
.colors('blue')
.group(grp2, "Bars")
.addFilterHandler(function(filters, filter) {return [filter];})
.centerBar(true),
dc.lineChart(composite)
.dimension(dim)
.colors('red')
.group(grp1, "Dots")
.dashStyle([2,2])
])
.render();
https://jsfiddle.net/gordonwoodhull/ronqfyj0/39/
I have created a line chart to display last three month data. It works fine except it only show two dates/months in x-axis (first and last). The label for middle point doesn't show.
linechart.js
self.chart = nv.models.lineChart()
.margin({left:100,botoom:50,top:0})
.useInteractiveGuideline(true)
.transitionDuration(350)
.showYAxis(true)
.showXAxis(true)
.showLegend(false)
.width(220)
.height(150)
self.chart.xAxis
.axisLabel('Month')
.tickFormat(function(d) {
return d3.time.format("%b-%Y")(new Date(d)); })
self.chart.yAxis
.axisLabel(myData[0].ylabel)
.tickFormat(d3.format(',.1f'));
myData = self.data;
Data
[{'y': 7L, 'x': u'2016-10'}, {'y': 2L, 'x': u'2016-11'}, {'y': 6L, 'x': u'2016-12'}]
Image
https://github.com/d3/d3-axis/blob/master/README.md#axis_tickValues
You need to set tickValues for your axis or d3 will generate them for you. Take a look at the snippet below:
chart.xAxis
.tickFormat(function(d) { return d3.time.format("%m/%d/%y")(new Date(d)); })
.tickValues(_.map(tick_values, function(d) { return getDate(d); }))
.rotateLabels(-30);
where tick_values is an array. For more info check the documentation above.
I am trying to create a composite of 2 line charts with dc.js.
But I get this error everytime:
Uncaught TypeError: timeChart.width(...).height(...).x(...).elasticY(...).margins(...).dimension(...).compose is not a function
it is a time series where I want to plot netCommercialPosition and netCommercialPosition as two seperate line. It works when I stack them but not when i want to use .compose.
I have followed several examples such as:
Dual Y axis line chart in dc.js
http://dc-js.github.io/dc.js/examples/series.html
So hopefully I use the .compose element correctly
my data set is a json with the following structure:
[{"CFTC_Commodity_Code": 1, "Net_Commmercial_Position": -113520, "Report_Date_as_MM_DD_YYYY": "14/07/2015", "Net_Fund_Position": -12246, "Price": 583.5, "Net_ Commmercial_Position": 3877, " },{…}]
here is my code:
d3.json("/donorschoose/COT", function (error, dataset1){
var ymdFormat = d3.time.format("%d/%m/%Y");
dataset1.forEach(function(p) {
p.Report_Date_as_MM_DD_YYYY = ymdFormat.parse(p.Report_Date_as_MM_DD_YYYY);
});
var COTProjects = dataset1;
var ndx = crossfilter(COTProjects);
var all = ndx.groupAll();
FilterDimension = ndx.dimension(function (d) {
return d.CFTC_Commodity_Code;
});
var dateDim = ndx.dimension(function(d) { return d.Report_Date_as_MM_DD_YYYY; });
var Prices = dateDim.group().reduceSum(function(d) {return d.Price; });
var netFundPosition = dateDim.group().reduceSum(function(d) {return d.Net_Fund_Position; });
var netCommercialPosition = dateDim.group().reduceSum(function(d) {return d.Net_Commmercial_Position; });
var minDate = dateDim.bottom(1)[0]["Report_Date_as_MM_DD_YYYY"];
var maxDate = dateDim.top(1)[0]["Report_Date_as_MM_DD_YYYY"];
var timeChart = dc.lineChart("#time-chart");
actualValuesChart = dc.lineChart(timeChart)
.group(netFundPosition)
normValuesChart = dc.lineChart(timeChart)
.group(netCommercialPosition)
timeChart
.width(650)
.height(260)
.x(d3.time.scale().domain([minDate, maxDate]))
.elasticY(true)
.margins({top: 0, right: 5, bottom: 20, left: 40})
.dimension(dateDim)
.compose([actualValuesChart,normValuesChart])
.transitionDuration(500)
.yAxis().ticks(4);
.brushOn(false)
FilterDimension.filter(1)
dc.renderAll();
});
Any help appreciated
thanks in advance
I found the solution, my problem was that I was trying to call compose() from a lineChart object instead of a compositeChart object.
dc.js-s doc
Here is an example using Queue.js to loading multiple csv in a dc.js : https://github.com/dc-js/dc.js/blob/master/web/examples/composite.html
Here is my version (javascript):
var composite = dc.compositeChart("#test_composed");
var composite2 = dc.compositeChart("#test_composed2");
var q = queue()
.defer(d3.csv, "morley.csv")
.defer(d3.csv, "morley2.csv");
q.await(function(error, exp1, exp2) {
var ndx = crossfilter();
ndx.add(exp1.map(function(d) {
return {x: d.Run};
}));
ndx.add(exp2.map(function(d) {
return {x: d.Run};
}));
var dim = ndx.dimension(dc.pluck('x')),
grp = dim.group().reduceCount(dc.pluck('x'));
composite
.width(768)
.height(480)
.x(d3.scale.linear().domain([0,200]))
.compose([
dc.barChart(composite)
.dimension(dim)
.group(grp)
])
.brushOn(false)
.render();
composite2
.width(768)
.height(480)
.x(d3.scale.linear().domain([0,200]))
.compose([
dc.lineChart(composite2)
.dimension(dim)
.group(grp)
])
.brushOn(false)
.render();
});
Using the same data, should be good as picture attached.
It worked very well for lineChart and barChart but not working for pieChart, rowChart...
Is there any similiar example for working pieChart?
Thanks!
I know this doesn't really solve your problem but I'm just letting you know of a different solution. Google code playground shows off some of the cool code google has for developers to use. Check out these links
Bar Chart: https://code.google.com/apis/ajax/playground/#bar_chart
Thanks for posting a jsfiddle. If you complete your fiddle, we can better help you troubleshoot it. ;-)
Looks like you are trying to create a composite chart with a pieChart. That's unusual - why do you want to do that? Normally a composite is for when you want to overlay different charts, but you've only got the one chart in your fiddle.
I'm not sure if the composite chart works with non-grid charts.