Please help me how can i change x-axis range of bullet chart to percentage?
i have this code of my NVD3.js bullet chart
nv.addGraph(function() {
var chart = nv.models.bulletChart();
chart.tooltip.valueFormatter(function(d){
return ''+ numberWithCommas(d)+''; //on hover show percentage and value
});
d3.select('#chart svg')
.datum(data)
.transition().duration(1000)
.call(chart);
return chart;
});
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
here's my data variable
var data = {
measureLabels: ["Total Obligated"]
measures:[0]
rangeLabels:["Available Amount"]
ranges:[28464000]
subtitle:"CODE"
title:"200000100003000"
}
i have tried to add this code
chart.xAxis.tickFormat(function(d) {
//return ranges * 100 / ranges
});
but it said that 'tickFormat' is not a function.
ok i figure out how to change it LOL!.
i added this code.
d3.selectAll('g.nv-tick').select('text').text(function (t) {
return (100 * t / data.ranges[0]).toFixed();
});
i tooks me half a day to figure it out T_T
Related
I have been trying to setup a common coloring scheme between a DC js pie chart and a series chart. I have created the coloring scale based on my requirement(need 20 colors for 20 topics) and then I tried to return the domain value through the colorAccessor function from the series chart. However, the colorAccessor function does not seem to work with the series chart as I tried to console.log(d) from within the colorAccesor function but nothing was logged on the console screen. And I guess that is the reason the colors are not being shared for same values across the pie chart and the series chart.
Here's my code
var TopicColorScale = d3.scale.ordinal().domain(["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","default"])
.range(["#18a3ad", "#b85436", "#3fe825","#e82825","#8793a5","#577c77","#c1f9a2","#f2c4cd","#a4f4f9","#003366","#fff4d8","#00245e","#e5ffd8","#471b1b","#ff6666","#ff9811","#11c7ff","#8fbec9","#b5b7e0","#ffc4d9","#f6ff02"]);
//d.key sample value : "topic6,internet,advertising,online" I am extracting the topic number for the domain and want a different color for each topic
topicChart.width(350)
.height(350)
.radius(160)
.innerRadius(30)
.dimension(maxtopicVal)
.title(function(d){ return "Topic : "+d.key+"\n Maxweight sum: "+d.value+'\n Percentage: '+ Math.round((d.endAngle - d.startAngle) / Math.PI * 50) + '%';})
.group(maxtopicValGroup)
.colorAccessor(function(d){
return d.key.split(",")[0].slice(5);
})
.colors(TopicColorScale);
This works fine and I get the desired colors on the pie chart. However, when I try to plot the same with the series chart, I get the colors from the scale but same value does not map to same color across the two charts. For example topic 1 has color red on the pie chart and has color blue on the series chart. The code for the series chart is as follows and was implemented after referring to this example : http://dc-js.github.io/dc.js/examples/range-series.html
focusChart
.width(920)
.height(380)
.chart(function(c) { return dc.lineChart(c).interpolate('cardinal').evadeDomainFilter(true); })
.x(d3.scale.linear().domain([1995,2017]))
.brushOn(false)
.yAxisLabel("Topic Weight")
.xAxisLabel("Year")
.elasticY(true)
.dimension(series1Dimension)
.group(series1Group)
.colorAccessor(function(d){
return d.key.split(",")[0].slice(5);
})
.colors(TopicColorScale)
focusChart.seriesAccessor(function(d) {return " " + d.key[0];})
.keyAccessor(function(d) {return +d.key[1];})
.valueAccessor(function(d) {return +d.value;})
.legend(dc.legend().x(400).itemHeight(13).gap(1).horizontal(10).legendWidth(540).itemWidth(210));focusChart.yAxis().tickFormat(function(d) {return d3.format('d')(d);});
focusChart.xAxis().tickFormat(function(d) {return d3.format('d')(d);});
focusChart.margins().left += 20;
I am unable to figure out what the problem is(Whether there is a problem in my code or not.) It would be great if any of you could help me with the common coloring scheme between the series chart and the pie chart or nudge me in the right direction! Thank you :)
I did have a similar problem when i did try to use the colorAccessor. My solution use the same color pallet to ordinalColors and in the series chart i create the sort function to seriesSort.
// code ...
graph.ufDimension = ndx.dimension(function(d) {
return d.uf;
});
graph.stateYearDimension = ndx.dimension(function(d) {
return [d.uf, +d.year];
});
graph.ufRateGroup = graph.ufDimension.group().reduceSum(function(d) {
return +d.rate;
});
graph.stateYearRateGroup = graph.stateYearDimension.group().reduceSum(function(d) {
return +d.rate;
});
// more code ...
graph.pallet=["#FF0000","#FF6A00","#FF8C00","#FFA500","#FFD700","#FFFF00","#DA70D6","#BA55D3","#7B68EE"]
// more code ...
this.lineRateStatesByYear
.width(fw)
.height(fh)
.margins({top: 0, right: 10, bottom: 45, left: 45})
.chart(function(c) { return dc.lineChart(c).interpolate('cardinal'); })
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.brushOn(false)
.yAxisLabel("km²/year")
.xAxisLabel(years[0].key + " - " + years[years.length-1].key)
.renderHorizontalGridLines(true)
.renderVerticalGridLines(true)
.title(function(d) {
return "Area/"+d.key[1]+": " + Math.abs(+(d.value.toFixed(2))) + " km²";
})
.elasticY(true)
.yAxisPadding('10%')
.dimension(this.stateYearDimension)
.group(this.stateYearRateGroup)
.mouseZoomable(false)
.seriesAccessor(function(d) {
return d.key[0];
})
.keyAccessor(function(d) {
return +d.key[1];
})
.valueAccessor(function(d) {
return +d.value;
})
.ordinalColors(graph.pallet)
.seriesSort(function(a,b) {
var rank=graph.ufRateGroup.top(Infinity);
var sr=[];
rank.forEach(function(d){
sr[d.key]=+d.value;
});
return d3.descending(sr[a], sr[b]);
})
.legend(dc.legend().x(fw - graph.lineRateStatesByYear.margins().right - 40).y(5).itemHeight(13).gap(7).horizontal(0).legendWidth(50).itemWidth(40));
this.pieTotalizedByState
.height(fh)
.width(parseInt(fw/4))
.innerRadius(10)
.externalRadiusPadding(30)
.dimension(this.ufDimension)
.group(this.ufRateGroup)
.title(function(d) {
return "Area: " + Math.abs(+(d.value.toFixed(2))) + " km²";
})
.label(function(d) {
return d.key + ":" + parseInt(Math.round(+d.value));
})
.ordinalColors(graph.pallet)
.legend(dc.legend().x(1).y(5).itemHeight(13).gap(7).horizontal(0).legendWidth(50).itemWidth(40));
I have a github repository to test and create my prototypes and the complete code is compound by files included in the entry point dashboard-prodes-rates.html. The main JS file is dashboard-prodes-rates-datatable.js where i put the charts implementation.
I am having two lines in th graph like in the picture having different X axis points. I just want to compare the lines. So I need to bring the second line under the first line (Normalize the graph like the second picture)
I tried to use nvd3 domain and range option and some others too. But its not working. Could you guys tell me how to get those normalized graph. I dont worry about the Tick format as far as the lines are comparable.
PICTURE 1 (the graph I am having)
https://www.dropbox.com/s/sycwppnlachju2s/Screenshot%20from%202014-06-19%2014%3A21%3A40.png
PICTURE 2 (Graph I need)
https://www.dropbox.com/s/eoajf0yyk96w6y7/Screenshot%20from%202014-06-19%2014%3A20%3A21.png
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart();
chart.xAxis
.tickFormat(d3.format(',f'));
chart.yAxis
.tickFormat(d3.format(',.2f'));
chart.y2Axis
.tickFormat(d3.format(',.2f'));
d3.select('#chart svg')
.datum(data)
.transition().duration(500)
.call(chart)
;
nv.utils.windowResize(chart.update);
return chart;
});
This is my data file. data.json
[{"key":"Memory_FREEmyses1","values":[{"x":"1395426430","y":"200028"},
{"x":"1395426431","y":"199904"},{"x":"1395426432","y":"187620"},
{"x":"1395426434","y":"187504"},{"x":"1395426435","y":"187380"},
{"x":"1395426436","y":"187008"},{"x":"1395426437","y":"186760"},
{"x":"1395426438","y":"186512"},{"x":"1395426439","y":"186388"},
{"x":"1395426440","y":"186264"},{"x":"1395426441","y":"181804"},
{"x":"1395426443","y":"181084"},{"x":"1395426444","y":"181084"}]},
{"key":"Memory_FREEmyses2","values":[{"x":"1395426455","y":"178604"},
{"x":"1395426456","y":"178348"},{"x":"1395426457","y":"178356"},
{"x":"1395426458","y":"178232"},{"x":"1395426460","y":"178108"},
{"x":"1395426461","y":"177860"},{"x":"1395426462","y":"177480"},
{"x":"1395426463","y":"176992"},{"x":"1395426464","y":"176868"},
{"x":"1395426465","y":"176620"},{"x":"1395426466","y":"176612"},
{"x":"1395426467","y":"176620"}]}]
Try to map your data like:
data = data.map(function(series) {
var d0 = series.values[0].x;
var dN = series.values[series.values.length -1].x;
series.values = series.values.map(function(d) {
return {
x: 10*(d.x-d0)/(dN-d0),
y: d.y
}
});
return series;
})
See demo.
I'm trying to draw the chart with data in following format:
[
{'label':'0', 'seconds':1094},
{'label':'1', 'seconds':1096},
{'label':'2', 'seconds':1112},
...
]
and the result looks like this:
It looks good and the question is:
How to customize the format of displaying Y value to this?:
UPDATE:
The code building the chart
nv.addGraph(function() {
var chart = nv.models.multiBarHorizontalChart()
.x(function(d) { return d.label })
.y(function(d) { return d.value })
.margin({top: 30, right: 20, bottom: 50, left: 20})
.showValues(true) //Show bar value next to each bar.
.tooltips(false) //Show tooltips on hover.
.transitionDuration(350)
.showControls(true); //Allow user to switch between "Grouped" and "Stacked" mode.
chart.yAxis
.tickFormat(d3.format(',.0f'));
d3.select('#chart1 svg')
.datum(jsonData)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
Try something like this
chart.yAxis.tickFormat(function(d) {
// %M - minute as a decimal number [00,59].
// %L - milliseconds as a decimal number [000, 999].
return d3.time.format('%M%L')(new Date(d))
});
UPDATE :
// Line Not Tested but valueFormat should do the trick
chart.valueFormat(d3.time.format('%M%L'));
Take a look at this if you need more time formatting options.
Hope it helps.
My chart repeats the values on the y axis. Is there a way I can only have 1,2,3 but nothing between (e.g the problem I have is shown on the chart below on the y axis):
The code im using is something like this:
nv.addGraph(function() {
var chart = nv.models.multiBarChart();
chart.xAxis
.tickFormat(function(d) { return d3.time.format('%x')(new Date(d)) });
chart.yAxis
.tickFormat(d3.format(',.1f'));
d3.select('#errorsFiredByDate')
.datum([{values: output, key: "Count by date"}])
.transition()
.duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
You have a few options to control the ticks in a D3 axis. You can specify the number of ticks explicitly using .ticks(), but this is more of a hint to the layout that may be disregarded. If you want to be absolutely sure about the ticks, use .tickValues() to set the tick values explicitly.
In your case, this would look something like this.
chart.yAxis.tickValues(d3.range(chart.yAxis.scale().domain()[0], chart.yAxis.scale().domain()[1]);
Other methods for figuring out the range may be more suitable, depending on your concrete application.
I was facing the same problem and I did this in chart options to fix
yAxis: {
tickFormat: function(d){
if ( (d * 10) % 10 === 0 ) {
return d3.format('.0f')(d);
}
else {
return '';
}
}
}
A late reply , but might be useful to others. I use a workaround to eliminate duplicate ticks, by maintaining an array of already applied ticks & d3's multi format specifier.
uniqueTicks = [];
xTickFormat = d3.time.format.multi([
["%Y", function (d) {
if (uniqueTicks.indexOf(d.getFullYear()) === -1) {
uniqueTicks.push(d.getFullYear());
return true;
} else {
return false;
}
}],
["", function () {
return true;
}]
]);
d3.svg.axis().tickFormat(xTickFormat );
This trick can be tweaked for any other type of tick format.
I'm using nvd3, but I think this is a general d3.js question about time scale and formatting. I've created a simple example that illustrates the problem (see code below):
If I omit .tickFormat for the xAxis, it works fine without date formatting. With the example below I get the error:
Uncaught TypeError: Object 1326000000000 has no method 'getMonth'
nv.addGraph(function() {
var chart = nv.models.lineChart();
chart.xAxis
.axisLabel('Date')
.rotateLabels(-45)
.tickFormat(d3.time.format('%b %d')) ;
chart.yAxis
.axisLabel('Activity')
.tickFormat(d3.format('d'));
d3.select('#chart svg')
.datum(fakeActivityByDate())
.transition().duration(500)
.call(chart);
nv.utils.windowResize(function() { d3.select('#chart svg').call(chart) });
return chart;
});
function days(num) {
return num*60*60*1000*24
}
/**************************************
* Simple test data generator
*/
function fakeActivityByDate() {
var lineData = [];
var y = 0;
var start_date = new Date() - days(365); // One year ago
for (var i = 0; i < 100; i++) {
lineData.push({x: new Date(start_date + days(i)), y: y});
y = y + Math.floor((Math.random()*10) - 3);
}
return [
{
values: lineData,
key: 'Activity',
color: '#ff7f0e'
}
];
}
The example (now fixed) is in nvd3 with date axis.
Try creating a new Date object before the tick for the x-axis gets passed to the formatter:
.tickFormat(function(d) { return d3.time.format('%b %d')(new Date(d)); })
See the documentation for d3.time.format to see how you can customize the formatting string.
Adding on to seliopou's answer, to correctly align the dates with the x-axis, try this:
chart.xAxis
.tickFormat(function(d) {
return d3.time.format('%d-%m-%y')(new Date(d))
});
chart.xScale(d3.time.scale()); //fixes misalignment of timescale with line graph