Change value on legend in dc.js - javascript

I built a pie chart with dc.js, with the following:
var chart = dc.pieChart(selector, this.chartGroup)
.width(200).height(200)
.dimension(this.dimension)
.group(this.group)
...
.legend(dc.legend().x(10).y(255).gap(5).horizontal(true))
chart.render()
Is there a way to format the labels on the legend with something like the following:
function (d) {
return d.key + ': ' + d.value;
}

The last answer seems partially true. I would suggest the following:
.legend(dc.legend().x(100).y(400).itemHeight(13).gap(5).autoItemWidth(true).legendText(function (d) {
return d.name + " " + Math.round((d.data / totalPrice) * 100) + "%"
}));
Where d.name is the actual label you will see in the legend.
d.data is the actual value.

I also needed to add (%) to the pieChart legend for several graphs. I ended up modifying a copy of the legend.js from dc.js-2.0.0-beta.5\src and include that in my pages.
See http://jsfiddle.net/za8ksj45/36/ for working example
The first ~260 lines is the modified legend.js that can be put in a separate file.
(I don't have a place I could serve it from so I had to include the file content).
The main modification starts at line ~88
itemEnter.append('text')
.text(function(d) {
var legendText = d.name;
if (_showPercent) {
var groupTotal = d.chart.group().all().reduce(function(a, v){ return a + v.value; }, 0);
//legendText = legendText + " (" + (100*d.data/groupTotal).toFixed(_percentDecimals) + "%)";
//legendText = legendText + " = " + (100*d.data/groupTotal).toFixed(_percentDecimals) + "%";
legendText = legendText + " - " + (100*d.data/groupTotal).toFixed(_percentDecimals) + "%";
}
return legendText;
})
.attr('x', _itemHeight + LABEL_GAP)
.attr('y', function () {
return _itemHeight / 2 + (this.clientHeight ? this.clientHeight : 13) / 2 - 2;
});
The modification consists of two new methods for legend()
.displayPercent (default=false to keep original behavior the same)
.percentDecimals (default=1)
The hardest part to figure out was the following line:
var groupTotal = d.chart.group().all().reduce(function(a, v){ return a + v.value; }, 0);
It calculates the grand total for the current filtered group that is driving the pieChart which can be used to calculate the percentage.
I played with a couple different string to show percentage. It should probably be replaced with a string like this: - (%%) where %% gets replaced with the actual percentage. That way you can customize it for each legend without having to touch the code.
Works great for a bunch of pieCharts I used so far. I wanted to share this on stackoverflow since I have gotten so much help from this site myself. If this is useful, I can expand it a bit and submit it for inclusion in some future release.

Now you can simply use the .legendText() method in the dc.legend() object!
In your particular case, the solution would be:
var chart = dc.pieChart(selector, this.chartGroup)
.width(200).height(200)
.dimension(this.dimension)
.group(this.group)
...
.legend(dc.legend().x(10).y(255).gap(5).horizontal(true).legendText(function(d) {
return d.key + ': ' + d.value;
}))
chart.render();
This method is defined here.

Related

Same random color on multiple pair of divs

So, I have a code where I generate a random color on page load.
$(function() {
$(".stuff").each(function() {
var hue = 'rgb('
+ (Math.floor((256)*Math.random()) + 25) + ','
+ (Math.floor((256)*Math.random()) + 25) + ','
+ (Math.floor((256)*Math.random()) + 25) + ')';
$(this).css("background-color", hue);
});
});
The color applies to the div .stuff. This div .stuff, works as a button. When I click .stuff, a relating div opens, which I call .filling.
.filling is not displayed on page load. When I click .stuff, both .stuff and .filling is displayed.
I have several .stuff, relating to their each .filling, creating pairs, so to speak.
The html:
<div id="port1Btn" class="divClick stuff">
</div>
<div id="port1" class="filling">
<img src="img/hyper.png">
</div>
The #port1Btn and #port1 is for defining the content of each pair, connecting them to the right button. And the divClick is for a script that helps close a open .filling when a .stuff is clicked.
Here is the code for that, if needed:
$('.divClick').bind("click", showFilling);
function showFilling(event) {
event.preventDefault();
var amountOfPorts = 999;
var ports = "";
for (i=0;i<amountOfPorts;i++) {
ports += "#port" + (i+1) +",";
}
ports = ports.slice(0, -1);
$(ports).hide();
var clickDiv = "#" + event.currentTarget.id;
var targetDiv = clickDiv.replace('Btn','');
$(targetDiv).toggle(100);
};
So, what I want to do is to have .stuff and .filling have their same color for each pair, but at the same time, every pair should have a different, random color on page load.
Thank you for reading, hope it was not too long, if so, let me know for future posts.
You can use the next() function.
$(function() {
$(".stuff").each(function() {
var hue = 'rgb('
+ (Math.floor((256)*Math.random()) + 25) + ','
+ (Math.floor((256)*Math.random()) + 25) + ','
+ (Math.floor((256)*Math.random()) + 25) + ')';
$(this).css("background-color", hue);
$(this).next(".filling").css("background-color",hue);
});
});
Adding that line will set the next div in the DOM after '.stuff' with the '.filling' class to the same color.

add Text inside the Boxgroup in heat map dc.js

is there a way to put a text inside the box group of a heat map in dc.js ?
so that the information is readable without making a hover on the box ?
var ndx2 = crossfilter(budgetsArr);
var budgetDimension = ndx2.dimension(function(d) {return [+d.account, +d.year]; });
var budgetGroup = budgetDimension.group().reduceSum(function(d) { return +d.budget; });
chart
.width(45 * 20 + 80)
.height(45 * 5 + 40)
.dimension(budgetDimension)
.group(budgetGroup)
.keyAccessor(function(d) { return +d.key[0]; })
.valueAccessor(function(d) { return +d.key[1]; })
.colorAccessor(function(d) { return +d.value; })
.title(function(d) {
return "Account: " + d.key[0] + "\n" +
"Year : " + d.key[1] + "\n" +
"Budget: " + (d.value) + " $";})
.colors(["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"])
.calculateColorDomain();
and the result :
I need that the Budget will be readable from the box and not in the title property.
Thank you!
Instead of appending the title add the text element try the following code. If it doesn't work put a plnkr link. I can probably help you to figure out the issue. Look at this link to understand more about adding the text element.
chart
.width(45 * 20 + 80)
.height(45 * 5 + 40)
.dimension(budgetDimension)
.group(budgetGroup)
.keyAccessor(function(d) { return +d.key[0]; })
.valueAccessor(function(d) { return +d.key[1]; })
.colorAccessor(function(d) { return +d.value; })
.append("text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", d.value/ 2)
.attr("dy", ".35em")
.text(function(d) { return "Account: " + d.key[0] + "\n" +
"Year : " + d.key[1] + "\n" +
"Budget: " + (d.value) + " $";}); });

Array values returning undefined in console/Round array elements to integers

I'm using the Highcharts JS charting library with the draggable points plugin for a project. I can set my array values up and have them generated fine. But when I try to change the Y value for any given array element by dragging the point up or down, the console returns the element as undefined. Any ideas why?
Code:
drag: function (e) {
// Returning false stops the drag and drops. Example:
$('#drag').html('Dragging <b>' + this.series.name + '</b>, <b>' + this.category + '</b> to <b>' + Highcharts.numberFormat(e.newY, 0) + '</b>');
},
drop: function () {
$('#drop').html('In <b>' + this.series.name + '</b>, <b>' + this.category + '</b> was set to <b>' + Highcharts.numberFormat(this.y, 0) + '</b>');
console.log( array.map(function(c) { return c[1]; }) );
}
Another problem is that the Y values aren't integers so if anyone knows how to round array elements to integers that could work
After updating point, format is changed from [x_value, y_value] to: {x: x_value, y: y_value}. So instead of c[1], use c.y for updated points. Since both formats are used you need to check which one is use.

nvd3 piechart.js - How to edit the tooltip?

I'm using nvd3's piechart.js component to generate a piechart on my site. The provided .js file includes several var's, as follows:
var margin = {top: 30, right: 20, bottom: 20, left: 20}
, width = null
, height = null
, showLegend = true
, color = nv.utils.defaultColor()
, tooltips = true
, tooltip = function(key, y, e, graph) {
return '<h3>' + key + '</h3>' +
'<p>' + y + '</p>'
}
, noData = "No Data Available."
, dispatch = d3.dispatch('tooltipShow', 'tooltipHide')
;
In my in-line js, I've been able to override some of those variables, like this (overriding showLegend and margin):
var chart = nv.models.pieChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.showLabels(false)
.showLegend(false)
.margin({top: 10, right: 0, bottom: 0, left: 0})
.donut(true);
I've tried overwriting the tooltip in the same way:
.tooltip(function(key, y, e, graph) { return 'Some String' })
but when I do that, my piechart does not display at all. Why can't I overwrite the tooltip here? Is there another way I can do so? I'd really rather not have to edit piechart.js itself at all; I need to keep that file generic for use in multiple widgets.
And while we're at it, is there some way I can make the entire tooltip into a clickable link?
Just override in this way it will work definitely
function tooltipContent(key, y, e, graph) {
return '<h3>' + key + '</h3>' +'<p>' + y + '</p>' ;
}
Or
tooltipContent(function(key, y, e, graph) { return 'Some String' })
I have just got the same problem, with nvd3 1.8.1, and this is the solution I've found.
Without the option useInteractiveGuideline you could simply declare your tooltip generating function in chart.tooltip.contentGenerator(function (d){ YOUR_FUNCTION_HERE}):
The argument d is given by nvd3 when calling the tooltip, and it has three properties :
value: the x-axis value for the cursor position
index: the index in chart's datum corresponding to the the cursor position
series: an array containing, for each item in the chart :
key: the legend key for that item
value: the y-axis value for that item at the cursor position
color: the legend color for that item
So here you have an example:
chart.tooltip.contentGenerator(function (d) {
var html = "<h2>"+d.value+"</h2> <ul>";
d.series.forEach(function(elem){
html += "<li><h3 style='color:"+elem.color+"'>"
+elem.key+"</h3> : <b>"+elem.value+"</b></li>";
})
html += "</ul>"
return html;
})
Important note
When the option useInteractiveGuideline is used, the chart.tooltip object isn't used to generate the tooltip, you must instead use the chart.interactiveLayer.tooltip, i.e.:
this.chart.interactiveLayer.tooltip.contentGenerator(function (d) { ... })
I hope the answer is useful for you, even if late.
Customized tooltip can not exist with "useInteractiveGuideline".
If you happen to use the Angular NVD3 wrapper, the way to set the custom message is through chart options, simply:
$scope.options = {
chart: {
...
tooltip: {
contentGenerator: function(d) {
return d.series[0].key + ' ' + d.series[0].value;
}
},
...
}
};
To add to previous answers, sometimes you want to use the data of the series and not only of x and y. For instance when
data = {'values': [{'month': 1, 'count': 2}, ...], 'key': 'test' }
For those situations, use
.tooltip(function(key, x, y, e, graph) {
var d = e.series.values[e.pointIndex];
return '<h3>' + e.series.key + '</h3><p>' + d.month.toString() + ...;
});
e.series is the particular series the mouse is hovering, e.pointIndex is the index on the values of the series. Here e.series.key == key, but I used to empathise what is e.series.
my_chart = nv.models.multiBarChart()
.tooltip(function(key, x, y, e, graph) {
return '<h3>' + key + '</h3>' +
'<p>' + y + ' on ' + x + '</p>';
});
I think you're missing the 'x' parameter in your tooltip function. The format of the function call is:
function(key, x, y, e, graph)
var chart = nv.models.multiBarChart();
chart.tooltip.contentGenerator(function (obj) {
return JSON.stringify("<b>HOHO</b>")
})
This worked for me...
chart:{
interactive:true,
tooltips: true,
tooltip: {
contentGenerator: function (d) {
return '<h3>PUT YOUR DATA HERE E.g. d.data.name</h3>'
}
}
Thank You and Best Regards
Abhay Patidar

JQuery: get a child as you append it

I am appending p tags to a div as I process a json request and would liek to style it according to what is in the request.
$(document).ready(function() {
function populatePage() {
var numberOfEntries = 0;
var total = 0;
var retrieveVal = "http://www.reddit.com/" + $("#addressBox").val() + ".json";
$("#redditbox").children().remove();
$.getJSON(retrieveVal, function (json) {
$.each(json.data.children, function () {
title = this.data.title;
url = this.data.url;
ups = this.data.ups;
downs = this.data.downs;
total += (ups - downs);
numberOfEntries += 1;
$("#redditbox").append("<p>" + ups + ":" + downs + " " + title + "<p>");
$("#redditbox :last-child").css('font-size', ups%20); //This is the line in question
});
$("#titlebox h1").append(total/numberOfEntries);
});
}
populatePage()
$(".button").click(function() {
populatePage();
});
});
Unfortunately things are not quite working out as planned. The styling at the line in question is applying to every child of the div, not just the one that happens to be appended at the time, so they all end up the same size, not sized dependent on their numbers.
how can I apply a style to the p tags as they are appended ot the div?
Edit: Thanks Fortes and Veggerby both worked, but i went with Fortes in the end because I did.
You can use JQuery's appendTo instead of append. For your example:
$("<p>" + ups + ":" + downs + " " + title + "<p>")
.css('font-size', ups%20)
.appendTo('#redditbox');
Here are the docs for appendTo: http://docs.jquery.com/Manipulation/appendTo
Replace:
$("#redditbox").append("<p>" + ups + ":" + downs + " " + title + "<p>");
with
var p = $("<p>" + ups + ":" + downs + " " + title + "<p>");
$("p", p).css('font-size', ups%20)
$("#redditbox").append(p);
Can probably be condensed even further.
Edit:
Condensed like:
$("#redditbox").append(
$("<p></p>").css('font-size', ups%20).append(ups + ":" + downs + " " + title + "")
);
Certain browsers/versions do not support the :last-child CSS selector. In that case they often ignore it and return all elements matching the remainder of the selector. This is possibly what you are seeing.
As usual IE is one such browser.
veggerby's approach should help you get around the need to use :last-child.

Categories

Resources