Adding icons to bar charts made using c3js - d3.js

I have made a stacked bar chart using c3 libraries and would like to add icons to each column (using c3 or d3). I went through their documentation but there doesnt seem to be any relevant functionality!
var chart = c3.generate({
data: {
columns: [
['data1', 30, 200, 100],
['data2', 130, 100, 140]
],
type: 'bar',
groups: [['data1', 'data2']]
},
});

You can import font-awesome and then (mis)use c3's label format configuration to set an icon for each series
var chart = c3.generate({
data: {
columns: [
['data1', 30, -200, -100, 400, 150, 250],
['data2', -50, 150, -150, 150, -50, -150],
['data3', -100, 100, -40, 100, -150, -50]
],
groups: [
['data1', 'data2']
],
type: 'bar',
labels: {
// format: function (v, id, i, j) { return "Default Format"; },
format: {
data1: function (v, id, i, j) { return "\uf1ec"; }, // a calculator
data2: function (v, id, i, j) { return "\uf212"; }, // a book
data3: function (v, id, i, j) { return "\uf1ae"; }, // a human
}
}
},
grid: {
y: {
lines: [{value: 0}]
}
}
});
You'll need this css rule -->
.c3-chart-text .c3-text {
font-family: 'FontAwesome';
}
And to import the FontAwesome css to get access to the glyphs (this may be an old version) -->
https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css
The glyph codes can be found here -->
https://fontawesome.com/cheatsheet
Example:
https://jsfiddle.net/h0g1fwpa/19/

Related

How to hide/show bars differentiate by a colors and by click on labels, using chartjs bar charts?

I am using chartjs to show one month attendance data, what I want to acheive is to show each day data with different colors like Present, absent and leave. I want labels on top and by click on that label user should be able to hide/show that particular label data, below is my code.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js" integrity="sha512-QSkVNOCYLtj73J4hbmVoOV6KVZuMluZlioC+trLpewV8qMjsWqlIQvkn1KGX2StWvPMdWGBqim1xlC8krl1EKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- HTML -->
<canvas id="chartJsDiv"></canvas>
<script>
function attendanceSummaryChart3(attendence)
{
var datasets = [];
var labels_data = [];
var num_of_hour = [];
var bar_colours = [];
var border_colr = [];
var real_data_count = attendence.length;
for (var i = 0; i < real_data_count; i++) {
var mydate = new Date(attendence[i].date);
var month = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"][mydate.getMonth()];
var str = mydate.getDate() + ' ' +month;
labels_data.push(str);
if(parseFloat(attendence[i].hours.replace(':','.')) < 6.00)
{
if(attendence[i].is_leave != null)
{
var applied_leave_type = attendence[i].is_leave_applied.leave_type.slug;
if(applied_leave_type == "work-from-home")
{
// Full hours in case work from home
num_of_hour.push('9');
bar_colours.push('RGB(25, 135, 84)');
border_colr.push('rgba(3, 126, 25, 0.85)');
// creating datasets
datasets.push({label: 'Work From Home', data: '9', backgroundColor: 'RGB(25, 135, 84)' });
}
else
{
// Leave applied
if(parseFloat(attendence[i].hours.replace(':','.')) == 0)
{
num_of_hour.push('-9');
bar_colours.push('RGB(25, 135, 84)');
border_colr.push('rgba(14, 8, 191, 0.8)');
// creating datasets
datasets.push({label: 'On Leave', data: '-9', backgroundColor: 'RGB(25, 135, 84)'});
}
else
{
num_of_hour.push(parseFloat(attendence[i].hours.replace(':','.')));
bar_colours.push('RGB(25, 135, 84)');
border_colr.push('rgba(14, 8, 191, 0.8)');
// creating datasets
datasets.push({label: 'Half Leave', data: parseFloat(attendence[i].hours.replace(':','.')), backgroundColor: 'RGB(25, 135, 84)'});
}
}
}
else
{
if(parseFloat(attendence[i].hours.replace(':','.')) == 0)
{
// If absent and no leave is applied
num_of_hour.push('-9');
bar_colours.push('RGB(255, 0, 0)');
border_colr.push('rgba(6, 108, 166, 0.8)');
// creating datasets
datasets.push({label: 'Absent (No Leave Applied)', data: '-9', backgroundColor: 'RGB(255, 0, 0)' });
}
else
{
// If present and didn't complete 06 hours in office
num_of_hour.push(parseFloat(attendence[i].hours.replace(':','.')));
bar_colours.push('RGB(255, 0, 0)');
border_colr.push('rgba(255, 99, 132, 1)');
// creating datasets
datasets.push({label: 'Present (Half Time)', data: parseFloat(attendence[i].hours.replace(':','.')), backgroundColor: 'RGB(255, 0, 0)' });
}
}
}
else
{
// Full hours
num_of_hour.push(parseFloat(attendence[i].hours.replace(':','.')));
bar_colours.push('RGB(0, 255, 0)');
border_colr.push('rgba(75, 192, 192, 1)');
// creating datasets
datasets.push({label: 'Present', data: parseFloat(attendence[i].hours.replace(':','.')), backgroundColor: 'RGB(25, 135, 84)' });
}
}
console.log(datasets);
const ctx = document.getElementById('chartJsDiv').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels_data,
datasets: [
{
label: ['Attendence'],
data: num_of_hour,
backgroundColor: bar_colours,
borderColor: border_colr,
}
]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
},
});
}
</script>
I am attaching a screenshot below currently I only have one label but I want multiple labels based on multiple colors bar
You need to use a second dataset to achieve this:
Then you can fill null values in both datasets where you dont use the values of that dataset, so null values on the places where value is negative in positive dataset and vice versa in other one.
Then you can use the property skipNull to make it so the bars dont take up space:
const options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, null, 3, 5, null, 3],
backgroundColor: 'green'
},
{
label: '# of Points',
data: [null, -11, null, null, -3, null],
backgroundColor: 'red'
}
]
},
options: {
skipNull: true
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.js"></script>
</body>
should be this part
label: ['Attendence', 'newLabel', 'xxx'],
under
const ctx = document.getElementById('chartJsDiv').getContext('2d');

How do I set the style for the legend data differently per dataset with Chart.js?

I have created a chart with Chart.js, and I now need to show the data in the legend differently per the two different datasets.
How do I show the first dataset 'Low/High Range Limit' in the classic rectangle/fill style and the dataset 'Patient Results' in the point style?
(Bonus: Currently, I'm showing the second dataset near-correctly. I also want to completely fill the circle with the solid 'steelblue' color, not with transparency.)
(I would provide an image but I need at least 10 reputation to post them.)
<style>
.chart-container { width: 550px }
</style>
<div class="chart-container">
<canvas id="myChart" width="2" height="1"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script>
var context = document.getElementById('myChart');
var myChart = new Chart(context, {
type: 'line',
data: {
labels: ['(A)', '(B)', '(C)', '(D)'],
datasets: [
{
label: 'Patient Results',
data: [40, 230, 30, 60],
borderColor: 'steelblue',
borderWidth: 2,
pointBackgroundColor: 'steelblue',
fill: false,
spanGaps: true // if true, lines will be drawn between points with no or null data. if false, points with NaN data will create a break in the line.
},
{
data: [0, 30, 20, 20], // representing the low range only
borderColor: '#222',
borderWidth: 2,
pointRadius: 0,
fill: true,
backgroundColor: '#fff'
},
{
label: 'Low/High Range Limit',
data: [60, 150, 50, 40], // representing the high range only
borderColor: '#222',
borderWidth: 2,
pointRadius: 0,
fill: true,
backgroundColor: '#c2e8f5'
}
]
},
options: {
elements: {
line: {
tension: 0 // disables bezier curves
}
},
legend: {
labels: {
boxWidth: 6,
filter: function(legendItem, chartData) {
if (legendItem.datasetIndex === 1) {
return false;
}
return true;
},
usePointStyle: true
},
position: 'right',
reverse: true // shows 'Low/High Range Limit' first
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>

How to draw Normalize Stack chart using C3 chart?

I want to draw normalize chart using C3 Chart library.
my current code is
var chart = c3.generate({
bindto: '#column-chart-main',
size: {
height: $('.chart-area').height()
},
data: {
rows:
chartFinalData
,
type: 'bar',
labels: {
format: d3.format('%')
},
colors: chartFinalColors,
transition: {
duration: 100
}
},
zoom: {
enabled: true
},
axis: {
y: {
show: false,
max: 1,
min: 0,
padding: {bottom:0}
},
x: {
type: 'category',
categories: chartFinalBrands
},
rotated: setChartType
},
tooltip: {
format: {
value:d3.format('%')
}
},
legend: {
show: $scope.chartTrans.showHideLegends,
position: 'inset',
inset: {
anchor: legendPosition,
x: 10,
y: 10,
step: legendSteps,
}
}
});
Above code generate simple bar stack chart.
but i need normalize bar stack chart
my current chart is - current-chart
i need chart as per - required-chart
Thanks in advance
If you want a normalised stack bar chart then you need to normalise the data first, c3 doesn't have a chart setting itself to work that out
e.g.
var data = [
['data1', 30, 200, 200, 400, 150, 250],
['data2', 130, 100, 100, 200, 150, 50],
['data3', 230, 200, 200, 300, 250, 250]
]
;
// Normalise
var scount = data.length;
for (var n = 1; n < data[0].length; n++) {
var total = 0;
for (var m = 0; m < scount; m++) {
total += data[m][n];
}
var ratio = 1.0 / total;
for (var m = 0; m < scount; m++) {
data[m][n] *= ratio;
}
}
var chart = c3.generate({
data: {
columns: data,
type: 'bar',
groups: [
['data1', 'data2', 'data3']
]
},
tooltip: {
format: {
value:d3.format('%')
}
},
axis : {
y : {
//max: 0.95, // for some reason this shows the last tick y as 100%, while 1.0 makes the last y tick 110%, don't know why
// thanks to a.n.onymous who figured out this worked better
max: 1,
padding: 0,
tick: {
format: d3.format("%")
}
}
}
});
http://jsfiddle.net/697p6hw5/6/

C3.js add color to an horizontal line

Is there a way in C3.js for to add COLOR to an horizontal line, the level 0 in axis y in bar graphs? By default you have this graph:
What I need is this:
Any idea? thanks.
UPDATE: I've made a line with this, but I need to add color.
grid: {
y: {
lines: [
{value: 0, text: ''}
]
}
}
In case anyone need it, this does the magic:
https://github.com/c3js/c3/issues/362#issuecomment-46377069
The reference has an example for horizontal (x-axis) lines: https://c3js.org/samples/grid_x_lines.html
// Copied from the reference
var chart = c3.generate({
data: {
columns: [
['sample', 30, 200, 100, 400, 150, 250],
['sample2', 1300, 1200, 1100, 1400, 1500, 1250],
],
axes: {
sample2: 'y2'
}
},
axis: {
y2: {
show: true
}
},
grid: {
y: {
lines: [
{value: 50, text: 'Label 50 for y'},
{value: 1300, text: 'Label 1300 for y2', axis: 'y2', position: 'start'},
{value: 350, text: 'Label 350 for y', position: 'middle'}
]
}
}
});
Also for x-axis lines (vertical): https://c3js.org/samples/grid_x_lines.html

Exclude zero values from a C3.js bar chart

Let's take for example following chart http://c3js.org/samples/chart_bar.html
but replace columns data with the data below:
var chart = c3.generate({
data: {
columns: [
['data1', 30, 0, 100, 0, 150, 250],
['data2', 130, 0, 140, 200, 0, 50]
],
type: 'bar'
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
// or
//width: 100 // this makes bar width 100px
}
});
setTimeout(function () {
chart.load({
columns: [
['data3', 130, -150, 200, 300, -200, 100]
]
});
}, 1000);
As we see we have a lot of white space or ZERO value bars, how can we remove it and remove white space. (not hide, I know how to hide it with CSS)
Image example, what should be removed
as googled in https://github.com/c3js/c3/issues/81
you need replace 0 to 'null' and add this:
line: {
connectNull: true,
},
var chart = c3.generate({
data: {
columns: [
['data1', 30, null, 100, null, 150, 250],
['data2', 130, null, 140, 200, null, 50]
],
line: {
connectNull: true,
},
type: 'bar'
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
// or
//width: 100 // this makes bar width 100px
}
});
setTimeout(function () {
chart.load({
columns: [
['data3', 130, -150, 200, 300, -200, 100]
]
});
}, 1000);
Just add
line: {
connectNull: true,
}
in your c3.generate block.
It will connect all points/bars/... on the chart with a zero value in between.
It works with null as well as with 0.

Resources