C3js horizontal bar chart labels cut off and sizing issue - javascript

I have a fixed size horizontal bar chart with rather long labels.
Main Question:
The label with the biggest data always gets cut off.
Additional Question (only nice to have.. ;) Is it possible in C3 to add margin between the bars?
Example with labels been cut off:
var colors = ['#0065A3', '#767670', '#D73648', '#7FB2CE', '#00345B'];
var padding = 5;
data= [
['veryveryveryveryverylongdatalabel01', 439034],
['veryveryveryveryverylongdatalabel02', 413664],
['veryveryveryveryverylongdatalabel03', 351376],
['veryveryveryveryverylongdatalabel04', 349932],
['veryveryveryveryverylongdatalabel05', 316490],
['veryveryveryveryverylongdatalabel06', 315039],
['veryveryveryveryverylongdatalabel07', 285908],
['veryveryveryveryverylongdatalabel08', 285681],
['veryveryveryveryverylongdatalabel09', 285215],
['veryveryveryveryverylongdatalabel10', 203248],
['veryveryveryveryverylongdatalabel11', 200508],
['veryveryveryveryverylongdatalabel12', 195508],
['veryveryveryveryverylongdatalabel13', 195058],
['veryveryveryveryverylongdatalabel14', 193508],
['veryveryveryveryverylongdatalabel15', 185508],
['veryveryveryveryverylongdatalabel16', 180508],
['veryveryveryveryverylongdatalabel17', 177508]
];
var totalDataValue = 0
data.forEach(function(d){
totalDataValue+=d[1];
});
var chart1 = c3.generate({
bindto: d3.select('#chart1'),
data: {
columns: data,
type: 'bar',
labels: {format : function(v, id) {return id + ": " + d3.format(",.0f")(v) + " ["+d3.format(".2%")(v/totalDataValue)+"]"; }}
},
bar: {
width: { ratio: 1}
},
legend: {
show: false,
},
tooltip: {
show: true,
format: {
value: function(value) {
return d3.format(",.0f")(value);
}
}
},
zoom: {
enabled: true
},
axis: {
x: {
show:false,
type:'category',
categories: ['value1']
},
y: {
show:false
},
rotated: true
}
});
#chart1 {
width: 600px;
height: 400px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.10/c3.min.css" rel="stylesheet" />
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.10/c3.min.js"></script>
<div id="chart1" class "c3">
</div>
It seems to be an internal C3 sizing issue.
Am I right there?
Is there a way to prevent the labels from beeing cut off?
thank you

You can set Y Axis top padding.
axis: {
y: {
padding : {
top: 430
}
},
rotated: true
}
You can also calculate top padding value based on length of largest label.

You could add an empty space by using a couple of "\u00A0" at the end of your labels format function:
data: {
labels: {format : function(v, id) {return id + ": " + d3.format(",.0f")(v)
+ " ["+d3.format(".2%")(v/totalDataValue)+"]"+"\u00A0\u00A0\u00A0\u00A0\u00A0"; }}
},
To set some space between the bars, add the bar.space parameter:
bar: {
space: 0.2
}
Below the code sipped:
var colors = ['#0065A3', '#767670', '#D73648', '#7FB2CE', '#00345B'];
var padding = 5;
data= [
['veryveryveryveryverylongdatalabel01', 439034],
['veryveryveryveryverylongdatalabel02', 413664],
['veryveryveryveryverylongdatalabel03', 351376],
['veryveryveryveryverylongdatalabel04', 349932],
['veryveryveryveryverylongdatalabel05', 316490],
['veryveryveryveryverylongdatalabel06', 315039],
['veryveryveryveryverylongdatalabel07', 285908],
['veryveryveryveryverylongdatalabel08', 285681],
['veryveryveryveryverylongdatalabel09', 285215],
['veryveryveryveryverylongdatalabel10', 203248],
['veryveryveryveryverylongdatalabel11', 200508],
['veryveryveryveryverylongdatalabel12', 195508],
['veryveryveryveryverylongdatalabel13', 195058],
['veryveryveryveryverylongdatalabel14', 193508],
['veryveryveryveryverylongdatalabel15', 185508],
['veryveryveryveryverylongdatalabel16', 180508],
['veryveryveryveryverylongdatalabel17', 177508]
];
var totalDataValue = 0
data.forEach(function(d){
totalDataValue+=d[1];
});
var chart1 = c3.generate({
bindto: d3.select('#chart1'),
data: {
columns: data,
type: 'bar',
labels: {format : function(v, id) {return id + ": " + d3.format(",.0f")(v) + " ["+d3.format(".2%")(v/totalDataValue)+"]"+"\u00A0\u00A0\u00A0\u00A0\u00A0"; }}
},
bar: {
width: { ratio: 1},
space: 0.2
},
legend: {
show: false,
},
tooltip: {
show: true,
format: {
value: function(value) {
return d3.format(",.0f")(value);
}
}
},
zoom: {
enabled: true
},
axis: {
x: {
show:false,
type:'category',
categories: ['value1']
},
y: {
show:false
},
rotated: true
}
});
#chart1 {
width: 600px;
height: 400px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.10/c3.min.css" rel="stylesheet" />
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.10/c3.min.js"></script>
<body>
<br><br>
<div id="chart1" class "c3">

I found a solution for preventing the labels from being cut-off.
Please see my following post on this:
Calculate padding for C3js horizontal bar charts
It's based on using global chart padding instead of using y-axis padding and turning off clip-path

Related

How to provide different labels in chart.js for toolbox and axis

I've provide a simple line chart with chart.js 3.7.0. How can I provide different labels for axis and toolbox? In my example I like to give empty lables besides 3 special values for the axis but the exact date value in the toolbox of a point.
My build:
<script>
chartLabels = ['2 years ago','', ... , '','1 year ago','', ... ,'','Today'];
chartData = [0,0, ... ,0,0.13,0.08, ... ,0,0.1];
yMax = 3;
</script>
<canvas id="chart-myvalues" width="160" height="90"></canvas>
In JS additionally:
const data = {
labels: chartLabels,
datasets: [{
label: 'My Value XYZ',
data: chartData,
tension: 0.5,
}]
};
const config = {
type: 'line',
data: data,
options: {
plugins: {
legend: {
display: false
}
},
scales: {
x: {
grid: {
display: false
},
ticks: {
autoSkip: false,
maxRotation: 0,
minRotation: 0
}
},
y: {
min: 0,
max: yMax,
grid: {
display: false
}
}
}
}
};
new Chart('chart-myvalue',config);
As asked for here is what I want exactly: In the screenshot above you see the 1 year ago once on the x axis and in the toolbox. On the x axis it is like I want it to. In the Toolbox I like to see the exact date of that value xyz (I can provide the date but I need to know how to provide different labels in chart.js for toolbox and axis)
It's called a tooltip and you can read more about it here. Basically, you have to make a callback to the title and label to change the x-axis and y-axis of the tooltip respectively. Here's how it would look:
boxLabels = ['2020-05-26', '2020-08-26', '2020-11-26', '2021-02-26', '2021-05-26', '2021-08-26', '2021-11-26', '2022-02-26', '2022-05-26'];
options: {
plugins: {
tooltip: {
callbacks: {
title: function(context) {
let title = context[0].label || boxLabels[context[0].dataIndex];
return title;
},
label: function(context) {
let label = context.dataset.label + ": " + context.dataset.data[context.datasetIndex];
return label;
}
}
}
}
};
Note that context for title returns an array, so you have to index it to get the element. See the snippet bellow for a whole example.
chartLabels = ['2 years ago','','','','1 year ago','','','','Today'];
chartData = [0,0,0,0,0.13,0.08,0,0,0.1];
yMax = 3;
boxLabels = ['2020-05-26', '2020-08-26', '2020-11-26', '2021-02-26', '2021-05-26', '2021-08-26', '2021-11-26', '2022-02-26', '2022-05-26'];
const data = {
labels: chartLabels,
datasets: [{
label: 'My Value XYZ',
data: chartData,
tension: 0.5,
}]
};
const config = {
type: 'line',
data: data,
options: {
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
title: function(context) {
let title = context[0].label || boxLabels[context[0].dataIndex];
return title;
},
label: function(context) {
let label = context.dataset.label + ": " + context.dataset.data[context.datasetIndex];
return label;
}
}
},
},
scales: {
x: {
grid: {
display: false
},
ticks: {
autoSkip: false,
maxRotation: 0,
minRotation: 0
}
},
y: {
min: 0,
max: yMax,
grid: {
display: false
}
}
}
}
};
new Chart('chart-myvalues',config);
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<canvas id="chart-myvalues" width="160" height="90"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.1/dist/chart.min.js"></script>
</body>
</html>

echart data point gradient color

I am trying to make a gradient line chart, The issue is with tooltip legend color and color of data points, they appear in brown gradient which was the default.
I was able to change the tooltip color, anyhow that is not the actual data point color but able to fix it to one color at least. whereas the points on the line do not pick up the color of the line.
Can someone point me in right direction?
var dom = document.getElementById("container");
var myChart = echarts.init(dom);
var app = {};
var option;
var data = [["2020-06-05",116],["2020-06-06",129],["2020-06-07",135],["2020-06-08",86],["2020-06-09",73],["2020-06-10",85],["2020-06-11",73],["2020-06-12",68],["2020-06-13",92],["2020-06-14",130],["2020-06-15",245],["2020-06-16",139],["2020-06-17",115],["2020-06-18",111],["2020-06-19",309],["2020-06-20",206],["2020-06-21",137],["2020-06-22",128],["2020-06-23",85],["2020-06-24",94],["2020-06-25",71],["2020-06-26",106],["2020-06-27",84],["2020-06-28",93],["2020-06-29",85],["2020-06-30",73],["2020-07-01",83],["2020-07-02",125],["2020-07-03",107],["2020-07-04",82],["2020-07-05",44],["2020-07-06",72],["2020-07-07",106],["2020-07-08",107],["2020-07-09",66],["2020-07-10",91],["2020-07-11",92],["2020-07-12",113],["2020-07-13",107],["2020-07-14",131],["2020-07-15",111],["2020-07-16",64],["2020-07-17",69],["2020-07-18",88],["2020-07-19",77],["2020-07-20",83],["2020-07-21",111],["2020-07-22",57],["2020-07-23",55],["2020-07-24",60]];
var dateList = data.map(function (item) {
return item[0];
});
var valueList = data.map(function (item) {
return item[1];
});
option = {
color: {
type: 'linear',
x: 0, y: 1,x2:0,y2:0,
colorStops: [{
offset: 0, color: '#00d4ff' // color at 0% position
}, {
offset: 1, color: '#090979' // color at 100% position
}],
global:true
},
// Make gradient line here
visualMap: [{
show: true,
type: 'continuous',
seriesIndex: 0,
min: 0,
max: 400
}],
title: [{
left: 'center',
text: 'Gradient along the y axis'
}],
xAxis: [{
data: dateList,
axisPointer: {
label:{
color:['#5470c6'],
}
},
axisLabel: {
formatter: function (value) {
return moment(value).format("MMM YY");
// And other formatter tool (e.g. moment) can be used here.
}
}
}],
yAxis: [{
type: 'value',
axisPointer: {
label:{
color:['#5470c6'],
}
}
}],
grid: [{
width:'auto',
height:'auto'
}],
tooltip : {
trigger: 'axis',
axisPointer: {
animation: true,
},
formatter: function (params) {
var colorSpan = color => '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + color + '"></span>';
let rez = '<p>' + params[0].axisValue + '</p>';
console.log(params); //quite useful for debug
params.forEach(item => {
// console.log(item); //quite useful for debug
var xx = '<p>' + colorSpan('#00d4ff') + ' ' + item.seriesName + ': ' + item.data + '</p>'
rez += xx;
});
console.log(rez);
return rez;
}
},
series: [{
color:['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
type: 'line',
showSymbol: false,
data: valueList,
// smooth: true,
label:{
show:true,
position:'top'
},
lineStyle:{
color: {
type: 'linear',
x: 0, y: 1,x2:0,y2:0,
colorStops: [{
offset: 0, color: '#00d4ff' // color at 0% position
}, {
offset: 1, color: '#090979' // color at 100% position
}],
global:false
}
}
}]
};
console.log(myChart);
if (option && typeof option === 'object') {
myChart.setOption(option);
}
You need to add gradientColor array to echarts options. Now echart will take care of changing color of tooltip and data point. You can also remove your custom tooltip formatted function.
gradientColor: ["#00d4ff", "#090979"]
Here the complete options object:
var data = [];
var dateList = data.map(function(item) {
return item[0];
});
var valueList = data.map(function(item) {
return item[1];
});
option = {
gradientColor: ["#00d4ff", "#090979"],
// Make gradient line here
visualMap: [
{
show: true,
type: "continuous",
seriesIndex: 0,
min: 0,
max: 400
}
],
title: [
{
left: "center",
text: "Gradient along the y axis"
}
],
xAxis: [
{
data: dateList,
axisPointer: {
label: {
color: ["#5470c6"]
}
},
axisLabel: {
formatter: function(value) {
return moment(value).format("MMM YY");
// And other formatter tool (e.g. moment) can be used here.
}
}
}
],
yAxis: [
{
type: "value",
axisPointer: {
label: {
color: ["#5470c6"]
}
}
}
],
grid: [
{
width: "auto",
height: "auto"
}
],
tooltip: {
trigger: "axis",
axisPointer: {
animation: true
}
},
series: [
{
type: "line",
showSymbol: false,
data: valueList,
// smooth: true,
label: {
show: true,
position: "top"
}
}
]
};

Highcharts - Change column color If data.point equal to string

I am creating a column type graph. Is there a way in javascript to change the color(which I want to define) of a column IF Gait == Walk
Here is an example of the graph im working on
https://jsfiddle.net/NRKSensors/4t6q5z0j/3/
$(function() {
Highcharts.setOptions({
colors: ['#ffffff', '#000000', '#666666']
});
var chart, merge = Highcharts.merge;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'column',
zoomType: 'x ',
marginTop: 20,
borderColor: null,
borderRadius: 20,
borderWidth: 2,
backgroundColor: null,
},
title: {
text: null
},
subtitle: {
text: null
},
data: {
csv: document.getElementById('csv').innerHTML,
seriesMapping: [{
x: 0, // Insert X values in minutes
y: 1, // Insert Y values (Frequency)
label: 2 // Insert Labels (Standing,Walk, Trot, Canter, Jump)
}]
},
tooltip: {
useHTML: true,
formatter: function() {
point = this.point;
html = '<table>';
html += point.label + '</h3></th></tr>';
html += '</table>';
return html;
},
followPointer: true,
hideDelay: 200
},
exporting: {
buttons: {
contextButton: {
enabled: false
}
}
}, // Gemmer Export Menu knappen. Den tror jeg ikke vi skal anvende.
credits: {
enabled: false
},
series: [{
type: 'column',
color: 'black'
}],
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<div id="container" style="width:100%; height:400px;"></div>
<pre id="csv" style="display:none">Touchdown,Frequency,Gait
22.414,100,"Walk"
22.42366667,100,"Walk"
22.43333333,103.4482759,Walk
22.44266667,96.77419355,Walk
22.45266667,96.77419355,Walk
24.69466667,136.3636364,Trot
24.70166667,125,Trot
24.70933333,136.3636364,Trot
24.71633333,120,Trot
24.72433333,130.4347826,Trot
25.11933333,68.18181818,Canter
25.13366667,88.23529412,Canter
25.14466667,85.71428571,Canter
25.156,88.23529412,Canter
</pre>
Do I need to prepare the data in the last column with qoutes?, so "Walk" instead of Walk?
Below is an example i made in Matlab. So I need to make it similar to this, but in highcharts
Matlab Column example
One way of doing this is to add a new column called color and set the value of this column based on the value of "Gait". This would be done in after highcharts have parsed the csv data like this:
data: {
csv: document.getElementById('csv').innerHTML, // Delete this line
seriesMapping: [{
x: 0, // Insert X values in minutes
y: 1, // Insert Y values (Frequency)
label: 2, // Insert Labels (Standing,Walk, Trot, Canter, Jump) NOT in quotes '' !!!
color: 3 //specify that column 3 is color
}],
parsed: function(columns) {
columns.push(['Color']) //Add a new column, color
for (var i = 0; i < columns[2].length; i++) {
if (columns[2][i] == 'Walk') {
columns[3].push('Red'); //Set color red for walk
} else if (columns[2][i] == 'Trot') {
columns[3].push('Blue');
} else if (columns[2][i] == 'Canter') {
columns[3].push('green');
} else { //Set grey for any gaits not found
columns[3].push('grey');
}
}
}
},
Working example: https://jsfiddle.net/ewolden/4t6q5z0j/40/
API on data.parsed: https://api.highcharts.com/highcharts/data.parsed

c3 categories tick formatting

I have a c3 bar graphing categories. I'd like to format the category label to be able to truncate it to a certain length. But i can't figure it out.
Here is the graph definition:
var chart;
chart = c3.generate({
padding: {
top: 20,
bottom: 20
},
data: {
columns: [
["Listeners",4,2,0],
["Listens",4,2,0]],
type: 'bar',
groups:[["Listeners", "Listens"]]
},
axis: {
x: {
type: 'category',
categories: ["012345678890", "012345678890", "012345678890"],
}
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
},
legend: {
show: false
}
});
<link href="https://raw.githubusercontent.com/c3js/c3/0.4.11/c3.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://raw.githubusercontent.com/c3js/c3/0.4.11/c3.js"></script>
<div id="chart" class="c3" style="max-height: 280px; position: relative;"></div>
I tried adding this to format the tick inside the x axis definition, but it complains that chart is not defined
tick:{format:function (x) { return chart.categories()[x].substring(0, 10); }}
Thanks in advance!
Of course, you just declare the variable var chart; that has no value, is undefined.
Try to create the chart config before the function c3.generate() then pass the config as argument.
var config = {
padding : {
top : 20,
bottom : 20
},
data : {
columns : [ [ "Listeners", 4, 2, 0 ], [ "Listens", 4, 2, 0 ] ],
type : 'bar',
groups : [ [ "Listeners", "Listens" ] ]
},
axis : {
x : {
type: 'category',
categories: ["012345678890", "012345678890","012345678890"],
}
},
bar : {
width : {
ratio : 0.5
}
},
legend : {
show : false
}
};
config.axis.x.tick = {
format : function(x) {
return config.axis.x.categories[x].substring(0,10)
}
};
var chart = c3.generate(config);
In your code, you have named categories in the x-axis definition, I'm not sure why you wouldn't just change the labels?
** EXAMPLE **
var chart;
chart = c3.generate({
padding: {
top: 20,
bottom: 20
},
data: {
columns: [
["Listeners",4,2,0],
["Listens",4,2,0]],
type: 'bar',
groups:[["Listeners", "Listens"]]
},
axis: {
x: {
type: 'category',
_comment: "THIS IS WHERE YOU SET YOUR CATEGORY LABELS",
categories: ["Label1", "Label2", "Label3"],
}
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
},
legend: {
show: false
}
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart" class="c3" style="max-height: 280px; position: relative;"></div>

Make simple bar chart using C3 with separate columns on the x axis

I'm trying to create a bar chart using C3 and D3 but I'm having trouble getting the columns to be unrelated to each other, other than for the fact that they use the same scale on the Y-axis.
I've included images to better explain.
var chart = c3.generate({
bindto: '#designerChart',
data: {
columns: [
['MA', 6],
['ME', 8],
['NY', 6],
['CN', 5],
['TX', 2]
],
type: 'bar',
},
axis: {
y: {
max: 10,
min: 0,
padding: { top: 0, bottom: 0 }
}
}
});
Results in a group of bars and when I hover over them I get the details for all the bars - not what I want.
I can change the data, so that it displays separate columns, but they are the same color and when I want to transition it to a pie chart you can't distinguish between the states.
var chart = c3.generate({
bindto: '#designerChart',
data: {
x: 'x',
columns: [
['x','MA', 'ME', 'NY', 'CN', 'TX'],
['rainfall', 6, 8, 6, 5, 4 ]
],
type: 'bar',
},
axis: {
x: {
type: 'category'
},
y: {
max: 10,
min: 0,
padding: { top: 0, bottom: 0 }
}
}
});
This is what I want:
Bar chart solution:
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/c3.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/c3.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>C3 Bar Chart</title>
</head>
<body>
<div id="designerChart"></div>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
columnColors = ['#9a4d6f', '#c76c47', '#f85115', '#d9b099', '#d4ba2f'];
function setColumnBarColors(colors, chartContainer) {
$('#' + chartContainer + ' .c3-chart-bars .c3-shape').each(function(index) {
this.style.cssText += 'fill: ' + colors[index] + ' !important; stroke: ' + colors[index] + '; !important';
});
$('#' + chartContainer + ' .c3-chart-texts .c3-text').each(function(index) {
this.style.cssText += 'fill: ' + colors[index] + ' !important;';
});
}
var chart = c3.generate({
bindto: '#designerChart',
data: {
columns: [
['rainfall', 6, 8, 6, 5, 4]
],
type: 'bar'
},
axis: {
x: {
label: {
text: 'States',
position: 'outer-center',
},
type: 'category',
categories: ['MA', 'ME', 'NY', 'CN', 'TX'],
tick: {
centered: true
}
},
y: {
label: {
text: 'Rainfall (inches)',
position: 'outer-middle'
},
max: 10,
min: 0,
padding: {
top: 0,
bottom: 0
}
}
},
legend: {
show: false
}
});
setColumnBarColors(columnColors, 'designerChart');
// Color turns to original when window is resized
// To handle that
$(window).resize(function() {
setColumnBarColors(columnColors, 'designerChart');
});
});
</script>
</body>
</html>
Colors turn to original in this fiddle (Full Page). But it changes colors as aspected on working local files , and local references of c3 , d3 ,and jquery.
References:
setColumnBarColors function:
jzcor...#gmail.com
https://groups.google.com/forum/
http://c3js.org/gettingstarted.html
http://c3js.org/samples/axes_x_tick_format.html
http://c3js.org/reference.html

Categories

Resources