d3.js pie chart - legend toggle - javascript

I'm working on a d3.js pie chart application. I am trying to develop the functionality that when you click on the legend rectangles, it toggles the slice on/off as well as the fill inside the legend rectangle.
Although there is a bug with an undefined function - but I am not sure why this error is occurring as the function is defined.
http://jsfiddle.net/Qh9X5/3261/
this.piedata = methods.pie(dataSet);
console.log("animate slice2", this.piedata);

This line (233) has turned your currentDataSet from an Array into an Object:
var currentDataSet = jQuery.extend(true, {}, methods.currentDataSet);
d3 then complains when it tries to call the map function on currentDataSet as it is expecting an array.
You need to change it to take an Array as the second parameter:
var currentDataSet = jQuery.extend(true, [], methods.currentDataSet);

Related

D3 - stack function bar chart filter

I have a codepen here - https://codepen.io/anon/pen/WdWyem?editors=1010
I have a simple stacked bar chart with a legend
I'm trying to use the legend to filter the bar chart.
When I click the colored block in the legend I'd like to remove that bar from the chart.
I have some basic data and I'm using D3's stack to create the stackedSeries and passing in the keys from an array 'keys'
I'm using the same 'keys' to create the legend and adding a class to each block that is the name of the key
When the block is clicked I wanted to capture the key name and remove it from the keys array and run the stack function again and redraw the chart.
This isn't working and I can't see how I can change the keys array and re-run the stack and
I haven't thought about getting the bars back yet.
stack = d3.stack()
.keys(getKeys());
function getKeys() {
console.log(keys)
return keys
}
function createStack() {
console.log('here');
stackedSeries = stack(dataToStack);
}
createStack();
To redraw the chart you need to recreate stack, so just move your stack creation into createStack function:
function createStack() {
stack = d3.stack()
.keys(getKeys());
console.log('here');
stackedSeries = stack(dataToStack);
}
Also you have to add the logic related to the colors of bars. For example you can change the colors array dynamically like you change the keys array

Getting access to already created Chart.js chart

I have created a BarChart with angular-chart like this:
<canvas id="bar"
chart-data="ctrl.barChartData"
chart-options="ctrl.barChartOptions"
chart-labels="ctrl.barChartLabels"
chart-series="ctrl.barChartSeries"
chart-click="ctrl.chartClick"
class="chart chart-bar">
</canvas>
I have wrote a chartClick function based on some example and looks like this:
vm.chartClick = function(evt){
var myBarChart = //how I can obtain a access to my created bar chart?
var activePoints = myBarChart.getPointsAtEvent(evt);
console.log("active: "+activePoints);
}
My question is: how can I obtain an access to chart I have created and assign it to myBarChart?
I have found solution for Highcharts however I can't find it for Chart.js
UPDATE:
Based on link provided by #IBarros I have manage to wrote following few lines of code:
$scope.$on('chart-create', function (event, chart) {
//console.log(chart);
myBarChart = chart;
});
I have 2 charts - one pie chart, one bar chart. What is more the event can be emitted multiple times for each chart so as a result I have a 7 charts printed into console. My next question is: how to find out what chart is a bar chart I'm looking for?
The reason why the event is fired 7 times was explained in this issue: How to get chart instance? #464
If options or other optional attributes are set after the data is set
the chart will be destroyed and recreated. This logic is what allows
the chart to be automatically updated everytime something changes in
the chart settings.
When that happens you should just update the reference on your side.
To figure out which chart object is the one you want, just look for the chart directive id (or chart type) in the chart object.
Example:
Use an object as an associative array
$scope.myCharts = {};
Save object reference in the associative array
$scope.$on('chart-create', function (event, chart) {
console.log(chart.chart.canvas.id);
console.log(chart.chart.config.type);
//If id is the same, reference will be updated
$scope.myCharts[chart.chart.canvas.id] = chart;
});
Access chart object by its directive id
console.log($scope.myCharts[id]);

DC.js Ordering with filters

Hi I am ordering the x values in my bar chart with .ordering. It orders correctly. However on filtering on other linked charts the ordering doesn't change. How do I achieve this behaviour?
Also ordering for me only works when I am overriding the default groupX.all() function with
groupX.all = function() {
return groupX.top(Infinity);
}
How can I make my bar chart order itself everytime it's redrawn?
How about this (untested):
chart.on('preRedraw', function() {
chart.rescale();
});
Since the ordering is implemented via the X scale, this should get the chart to recompute the scale each time.

Plot within a tooltip in d3.js

I would like to create a d3-based plot which graphs a plot within a tooltip. Unfortunately, I haven't found any examples on the web. Here is a sample JSON file.
[{"x":[0.4],
"y":[0.2],
"scatter.x":[0.54,0.9297,0.6024,-1.9224,2.2819],
"scatter.y":[0.4139,1.1298,-0.1119,2.3624,-1.1947]},
{"x":[0.1],
"y":[0.9],
"scatter.x":[-0.8566,-0.5806,-0.9326,0.8329,-0.5792],
"scatter.y":[-0.5462,-0.7054,1.0264,-3.4874,-1.0431]}]
The idea is to have a scatter plot for (x,y) coordinates first. However, when one mouses over a point, a different scatter plot within a tooltip appears based on [scatter.x, scatter.y] coordinates for that respective point.
I can do the scatter plots separately but have been struggling to put them together. Could anyone shed some light on this and/or provide a minimal example?
This was too long for a comment but I'm not certain if it's the answer you were looking for. One of the issues you might find is that your nested data is formatted differently-- one uses JSON objects with x and y, while the other uses two arrays of points.
My solution to this would be to create an extensible function:
function makeScatterPlot(elem, width, height, data, fill)
elem, width, height, and data are the core parameters: which element to attach the chart to, the size of the chart, and the data for the chart (in the JSON object format).
This function would generate all necessary items for the chart and add the chart to the provided element.
Then you want to bind to mouseover of your main chart, and in that function you'll have to do a bit of data modification to re-organize the two arrays into the JSON object structure.
function mainMouseover(d){
var newData = [];
for (var i = 0; i < d["scatter.x"].length; i++){
var t = {x: [0], y: [0]};
t.x[0] = d["scatter.x"][i];
t.y[0] = d["scatter.y"][i];
newData.push(t);
}
var newG = mainG.append("g").attr("transform", "translate(200,200)");
makeScatterPlot(newG, 100,100, newData, "red");
}
Of course, you would modify the translate to match wherever you want your tooltip to be.
Putting this all together you get the following (very crude) fiddle. Hover over either of the black dots to see the sub-chart. Obviously this needs quite a bit of work to be a solid example (i.e. remove the sub-chart on mouseout), but hopefully it will set you in the right direction.
If the tooltip chart is significantly different styling-wise compared to your main chart it may not be the best idea to use an extensible function, and you could just create another custom function instead.

Setting pie chart colors using d3.js

I'm having issues setting pie slice colors using a d3.pieChart. Documentation and examples I've seen use the colors method in combination with an array of hex colors. However, setting this results in my pie chart being colored white (invisible) and every item in the legend becoming black.
I've tried using .colors with an array of five and an array of six colors but the issue persists. Could this be due to some issue with the slicesCap?
Code snippet below, but category10 burns my eyes so any advice on implementing a custom color set would be appreciated!
pie
.slicesCap(5)
.legend(dc.legend().gap(3))
.colors(d3.scale.category10())
Just passing an array of colour values doesn't work because the .colors() function is expecting a color scale like the one created by d3.scale.category10(). Scales are functions which take input data and return a value; in this case, the returned value is one of 10 colours.
For starters, you could try one of the other d3 built-in colour scales, which don't have as extreme contrast:
https://github.com/mbostock/d3/wiki/Ordinal-Scales#wiki-category20
If none of those suit, you can make your own scale function with
var colorScale = d3.scale.ordinal().range([/*array of hex values */]);
pie.colors(colorScale);
You can create the array yourself or use one of the colorBrewer functions.
If you want to specify particular colours for particular values (instead of just assigning the colours to values in the order they appear) you'll need to (a) specify the domain of the scale as an array of values that matches the order of the range array, and (b) create a helper function that passes in the correct property from your data:
var colorScale = d3.scale.ordinal().domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);
pie.colors(function(d){ return colorScale(d.fruitType); });
You can assign colors to particular values like this.
var colorScale = d3.scale.ordinal()
.domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);
pie.colors(colorScale.range())
.colorAccessor(function(d){ return colorScale.domain().indexOf(d.fruitType); });
This solution is a little bit hacky, but I couldn't get it to work using only chart.colorDomain, and calling a function in chart.colors seems to be throwing errors now.
Riffing off Tayden's answer, there is slightly different syntax for newer versions of d3 (i.e. "scaleOrdinal")
var colorScale = d3.scaleOrdinal()
.domain(["banana", "cherry", "blueberry"])
.range(["#eeff00", "#ff0022", "#2200ff"]);

Categories