I have a C3 chart,
I would like to add a label on each point reading its y value with a percentage symbol appended to it.
e.g. 400%.
There is a solution for bar charts
labels: {
format: {
y: d3.format("$,")
//y: function (v, id) { return "Custom Format: " + id; }
}
But this doesn't work for line graphs.
There is also good answer on custom labels for bar charts, however, this doesn't seem to transfer to line charts.
There is this good answer on custom tooltips, but I can't work out how to do custom labels in a line graph.
Attempt: http://jsfiddle.net/7kYJu/6547/
Also, for some reason using % will prevent the graph from appearing, whereas $ will work, e.g
y: d3.format("$,")
Try This
`var chart = c3.generate({
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 130, 100, 140, 200, 150, 50]
],
type: 'line',
labels: {
format: {
data1: d3.format("$,")
//data1: function (v, id) { return "Custom Format: " + id; }
}
}
}
});`
it should be the data array and not the axis to be mentioned as key in format object
Related
I am looking to create a donut chart where instead of the pieces of the pie showing the percentage of the total, i'd like it to highlight the label/legend for each element?
I have tried using the formatter function e.g.
formatter: function(value, { seriesIndex, dataPointIndex, w }) {
return w.config.series[seriesIndex].name + ": " + value.toFixed(0)+ " %"
},
But this generates labels on each of the donut segments - undefined: 26 %
Would appreciate any thoughts on how to do this.
Many thanks,
Nigel
For donut charts, the labels are stored separately from the data value (i.e. series).
When creating the chart you'll pass these values:
options = {
series: [44, 55, 13, 33],
labels: ['Apple', 'Mango', 'Orange', 'Watermelon']
}
Or if using React/Vue:
series: [44, 55, 13, 33],
chartOptions: {
labels: ['Apple', 'Mango', 'Orange', 'Watermelon']
}
(Both examples from the documentation, with slight modification.)
This means that to access the labels in the formatter function, we need to reference labels instead of series. We can also drop the .name.
formatter: function(value, { seriesIndex, dataPointIndex, w }) {
return w.config.labels[seriesIndex] + ": " + value.toFixed(0)+ " %"
},
I've been trying for 3 days to get this chart to display the way I want it to. Everything was working 100% until I realized the grouped bar chart numbers were off.
Example: When the bottom bar value equals 10 and the top bar value equals 20, the top of the grouped bar read 30. This is the default behavior, but not how I want to represent my data. I want the top of the grouped bar to read whatever the highest number is, which lead me to this fiddle representing the data exactly how I wanted to.
After refactoring my logic, this is what I have so far. As you can see the timeseries line is broken up and the tooltip is not rendering the group of data being hovered over.
My questions:
1) How to get the tooltip to render all three data points (qty, price, searches)
2) How to solidify the timeseries line so it's not disconnected
Any help would be greatly appreciated so I can move on from this 3 day headache!
Below is most of my code - excluding the JSON array for brevity, which is obtainable at my jsfiddle link above. Thank you in advance for your time.
var chart = c3.generate({
bindto: '#chart',
data: {
x: 'x-axis',
type: 'bar',
json: json,
xFormat: '%Y-%m-%d',
keys: {
x: 'x-axis',
y: 'searches',
value: ['qty', 'searches', 'price']
},
types: {
searches: 'line'
},
groups: [
['qty', 'price']
],
axes: {
qty: 'y',
searches: 'y2'
},
names: {
qty: 'Quantity',
searches: 'Searches',
price: 'Price ($)'
},
colors: {
price: 'rgb(153, 153, 153)',
qty: 'rgb(217, 217, 217)',
searches: 'rgb(255, 127, 14)'
}
},
bar: {
width: {
ratio: 0.60
}
},
axis: {
x: {
type: 'timeseries',
label: { text: 'Timeline', position: 'outer-right' },
tick: {
format: '%Y-%m-%d'
}
},
y: {
type: 'bar',
label: {
text: 'Quantity / Price',
position: 'outer-middle'
}
},
y2: {
show: true,
label: {
text: 'Searches',
position: 'outer-middle'
}
}
},
tooltip: {
grouped: true,
contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
var data = this.api.data.shown().map(function(series) {
var matchArr = series.values.filter(function(datum) {
return datum.value != undefined && datum.x === d[0].x;
});
if (matchArr.length > 0) {
matchArr[0].name = series.id;
return matchArr[0];
}
});
return this.getTooltipContent(data, defaultTitleFormat, defaultValueFormat, color);
}
}
});
1) If I got it right, you want tooltip to show all values, even if some of them are null.
Null values are hidden by default. You can replace them with zero (if it is suitable for your task) and thus make them visible.
Also, it seems to me that there is a shorter way to get grouped values:
var data = chart.internal.api.data().map(function(item) {
var row = item.values[d[0].index]; // get data for selected index
if (row.value === null) row.value = 0; // make null visible
return row;
});
2) I think you are talking about line.connectNull option:
line: {
connectNull: true
}
UPDATE
Looks like having duplicate keys breaks work of api.data() method.
You need to change json structure to make keys unique:
Before:
var json = [
{"x-axis":"2017-07-17","qty":100},
{"x-axis":"2017-07-17","price":111},
{"x-axis":"2017-07-17","searches":1},
{"x-axis":"2017-07-18","qty":200},
{"x-axis":"2017-07-18","price":222},
{"x-axis":"2017-07-18","searches":2}
];
After:
var json = [
{"x-axis":"2017-07-17","qty":100,"price":111,"searches":1},
{"x-axis":"2017-07-18","qty":200,"price":222,"searches":2}
];
See fiddle.
js is a very good library, but I have a problem:
in my graph each bar represents a value produced between two hours, but the tick text is below the bar and I want to get it between the bar !
my type of x-axis is "type: 'category'"
data = ['x', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00']
Can someone help me?
Thank you in advance.
I have :
http://hpics.li/9fc4863
I want :
http://hpics.li/1fb1090
You could convert your x axis to a timeseries and have the values tagged to the actual midpoint of your hour ranges (12.30, 1.30...)
var chart = c3.generate({
data: {
x: 'x',
columns: [
['x',
new Date('2013-01-01T00:30'),
new Date('2013-01-01T01:30'),
new Date('2013-01-01T02:30'),
new Date('2013-01-01T03:30')],
['data1', 30, 200, 100, 400]
],
type: 'bar'
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%H:%M',
values: [
new Date('2013-01-01T00:00'),
new Date('2013-01-01T01:00'),
new Date('2013-01-01T02:00'),
new Date('2013-01-01T03:00'),
new Date('2013-01-01T04:00')
],
rotate: -90
},
height: 50
}
}
});
Fiddle - http://jsfiddle.net/v4z45zzj/
I have a c3js line graph of type timeseries.
My axis tables are currently like this:
11/10.....05/11.....11/11.....05/12.....11/12.....05/13.....11/13
and it want it to be
.12/10.....06/11.....12/11.....06/12.....12/12.....06/13.....
where each dot indicates a month, note that the datapoint at 11/10 is still kept and displayed, only the axis labelling has changed. FYI, The increment is not set directly but hacked using culling.
Is there any way to alter the starting label to 12/10 (with all subsequent labels increasing in 6-months intervals)?
UPDATE (14NOV14): I have added a working jsFiddle for you to tinker with. Any help is appreciated!
UPDATE (14NOV14): I have tried using functions for this. But I want the 'pop-up' box to show the grey heading all the time.
This was a painfully long learning process, for a very badly-documented library. But I had to use a function for the format option for the tick, and then format the title again for the tooltip. Here's the final, working copy.
HTML (Include the d3.js, c3.js, and c3.css scripts too)
<body>
<div id="chartContainer"></div>
</body>
JS
var chart = c3.generate({
bindto: '#chartContainer',
data: {
x: 'x',
columns: [
['x', '2013-04-01', '2013-05-02', '2013-06-03', '2013-07-04', '2013-08-05', '2013-09-06'],
['data1', 30, 200, 100, 400, 150, 250],
['data2', 130, 340, 200, 500, 250, 350]
]
},
axis: {
x: {
type: 'timeseries',
tick: {
format: function (x) {
if((x.getMonth()+1) % 6 === 0) {
return ('0' + (x.getMonth()+1)).slice(-2) + '/' + x.getFullYear().toString().substr(2,2);
}
}
}
}
},
tooltip: {
format: {
title: function (d) {
var format = d3.time.format('%m/%y');
return format(d)
}
}
}
});
N.B. Also be aware that culling might interfere with this. I had to set culling: {max: 100} to ensure any built in incrementations are not applied.
I am working with a bar chart in jqPlot where I need to show the average with a separate line on the chart. My question is how to do that? Would I need to use a Line chart for this? I have looked at few Line chart examples but they are shown as a trend in the bar chart which starts from the very first bar on the chart rather than showing the average.What I need is plotting a line using the average of all those bars displayed on the chart (screen shots as below)
My JSON string to plot the data is as follows:
var commonOption= {
title: ''
,stackSeries: true
,captureRightClick: true
,seriesDefaults:{
renderer:$.jqplot.BarRenderer
,rendererOptions: {
barMargin: 15
,highlightMouseDown: true
,fillToZero: true
},
pointLabels: {
show: true
,formatString: '%.1f'
,seriesLabelIndex:1
,hideZeros:false
}
}
,seriesColors: ['#A9CB5E']
,axes: {
xaxis: {
tickOptions:{angle:-45}
,tickRenderer: $.jqplot.CanvasAxisTickRenderer
,renderer: $.jqplot.CategoryAxisRenderer
,ticks: []
},
yaxis: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
,padMin: 0
,pad: 1.1
, label: 'Percentage (%)'
,rendererOptions: { forceTickAt0: true}
//,min: 0
//,tickOptions:{formatString: '%.0f'},
}
}
,negativeSeriesColors:['#F08080']
/*,legend: {
show: true
,location: 'e'
,placement: 'outsideGrid'
}*/
,highlighter:{
show: true
,tooltipLocation: 's'
,yvalues: 2
,bringSeriesToFront:true
,showMarker:false
,tooltipAxes: 'y'
,formatString: "%n%s"
}
,cursor:{
show: true
,zoom:true
,showTooltip:false
,constrainZoomTo: 'y'
}
,grid:{
background: '#f8f8f8'
}
};
I believe what you are looking for is the jqplot CanvasOverlay functionality http://www.jqplot.com/deploy/dist/examples/canvas-overlay.html
After declaring all of you options and data in the function (in your example after "grid" option):
grid:{
background: '#f8f8f8'
},
canvasOverlay: {
show: true,
objects: [
{horizontalLine: {
name: 'avergae',
y: 20.8, //**AVERAGE_FLOAT_VALUE**
lineWidth: 2,
color: 'black',
shadow: false
}}
]
}
EDIT:
Yes, sorry about that. be sure not to forget to include "jqplot.canvasOverlay.min.js "
Hi I think it is better to implement a function that automatically calculates the average of the data points into the array. In fact the average of your bar char is about 18 and not 20!!
I suggest to implement a function for doing thi. See this jsFiddle example.
There is an article where it is shown how to draw and calculate the statistics for a bar chart: average, median, mode and standard deviation at this link:
http://www.meccanismocomplesso.org/en/mean-mode-median-barchart/ .
Array.prototype.average=function(){
var sum=0;
var j=0;
for(var i=0;i<this.length;i++){
if(isFinite(this[i])){
sum=sum+parseFloat(this[i]);
j++;
}
}
if(j===0){
return 0;
}else{
return sum/j;
}
}
...
canvasOverlay: {
show: true,
objects: [
{dashedHorizontalLine: {
name: 'average',
y: data.average(),
lineWidth: 3,
color: 'black',
shadow: false
}}
]
}