chart.js v4 truncate scale/labels - javascript

similar questions has been asked here in the past but eventually for older versions of Chart.js. The accepted answers of the questions didn't work.
I have a chart like this:
The code of this chart is this:
new Chart(
document.getElementById("chart-01"), {
type: 'bar',
data: {
labels: ["Test loooooong 1", "Test loooooong 2", "Test loooooong 3"],
datasets: [{ data: [574.48, 140.93, 64.37]}]
},
options: {
scales: {
y: {
ticks: {
callback: function(value) {
return '$ ' + value;
}
}
},
// x : {
// ticks : {
// callback : function(value, index, ticks) { return value.split(0,8)+'...';}
// }
// }
},
plugins: {
legend: {
display: false
}
}
}
}
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.umd.js" integrity="sha512-vCUbejtS+HcWYtDHRF2T5B0BKwVG/CLeuew5uT2AiX4SJ2Wff52+kfgONvtdATqkqQMC9Ye5K+Td0OTaz+P7cw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<canvas id="chart-01" width="500" height="600"></canvas>
I am trying to truncate the names on the x-axis after 8 chars and add a '...', So if I am using that commented code block:
x : {
ticks : {
callback : function(value, index, ticks) { return value.split(0,8)+'...';}
}
}
I get the error message:
Uncaught (in promise) TypeError: value.split is not a function
Also if I use only the value, without split, I get numbers back but not the label names.
This are links to solutions that did not work for me.
https://stackoverflow.com/a/39537545/3408158
https://stackoverflow.com/a/44418430/3408158
What am I doing wrong?

To get/change the value of the label you have to use the function getLabelForValue.
(here an example from the documentation)
And split is the incorrect function you would need to use substring.
(link to the mdn documentation)
Here all the fixes entered into your example code:
new Chart(document.getElementById("chart"), {
type: 'bar',
data: {
labels: ["Test looooong 1", "Test looooong 2", "Test looooong 3"],
datasets: [{ data: [574.48, 140.93, 64.37]}]
},
options: {
scales: {
y: {
ticks: { callback: value => `$ ${value }` }
},
x: {
ticks: {
callback: function(value){
let newLabel = this.getLabelForValue(value)
.substring(0,8) + '...';
return newLabel;
}
}
}
}
}
});
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="height:184px; width:350px;">
<canvas id="chart" ></canvas>
</div>
Information: The mentioned solutions don't worked because, as far as I can tell, they are base on he chartjs Verion 2.0+, and since then the chartjs library change substantially.

Related

t[this.activeSeriesIndex].data[0] is undefined in ApexCharts. How to correctly build the series array?

I'm a beginner in Vue and I'm using vue-apex chart to create a chart in my application. I want to display in chart, the values of the two component's properties "uncorrectAns" and "correctAns" that I compute thanks to a specific method (computeStat()).
<template>
<apexcharts width="500" type="bar" :options="chartOptions" :series="series"></apexcharts>
</template>
<script>
export default {
name: 'Results',
components: {
apexcharts: VueApexCharts
},
data() {
return {
results: '',
correctAns: 0,
uncorrectAns: 0,
chartOptions: {
chart: {
id: 'vuechart-example'
},
xaxis: {
categories: ['Correct Answers', 'Uncorrect Answers']
}
},
series: [
{
name: 'series-1',
data: [this.correctAns, this.uncorrectAns]
}
]
}
},
methods: {
computeStat() {
var i
for (i = 0; i < this.results.length; i = i + 1) {
if (this.results[i].answerCorrect == true) {
this.correctAns = this.correctAns + 1
} else {
this.uncorrectAns = this.uncorrectAns + 1
}
}
}
},
created() {
this.results = this.$route.params.output
this.computeStat()
var i
for (i = 0; i < this.results.length; i = i + 1) {
console.log('bestPractice ' + i + ':' + this.results[i].bestPract)
}
}
}
</script>
When I run the application, the chart isn't displayed and I get this error message on the browser console:
I would like to know the nature of this error and if there is a correct way to display "correctAns" and "uncorrectAns" values in the chart.
There's a couple of problems here around your series property...
When you define series, both this.correctAns and this.uncorrectAns are undefined (this is the source of your problem)
Because series is statically defined, it will never update as you make changes to this.correctAns and this.uncorrectAns
The solution is to convert series into a computed property. Remove it from data and add
computed: {
series () {
return [
{
name: 'series-1',
data: [this.correctAns, this.uncorrectAns]
}
]
}
}
Demo ~ https://jsfiddle.net/ynLfabdz/
Given you seem to be treating results as an array, you should initialise it as such instead of an empty string, ie
results: [], // not ''
I fixed the issue by simple check if the array is undefined then return empty if not return the chart with my values
const Amount = [
{
name: 'Salary Amount',
data: salary[0] === undefined ? [] : salary
},
{
name: 'Over Time Amount',
data: overTime[0] === undefined ? [] : overTime
},
true
]

Decide which serie goes into range-selector highstock

I have a chart with 3 different series and I've included Range Selector from Highstock. I want to be able to select which one of the 3 series is the one set in the Range-Selector. Is there any way to dynamically assign the serie to the Range Selector?
I create the chart with 3 series like this:
//A,B,C data array
Highcharts.stockChart('container', {
series: [
{ data: A },
{ data: B },
{ data: C }
]
});
What I want to accomplish is to be able to select either A,B or C as the serie active to see in the Range-Selector preview.
Here's a jsfiddle: https://jsfiddle.net/usvonfjh/1/
You can show each series in navigator by setting series.line.showInNavigator = true. To set it dynamically use series.update() method where you can pass new options for series.
Code:
let dates = [1496268000000, 1504216800000, 1512082800000, 1519858800000, 1527804000000, 1535752800000, 1543618800000, 1551394800000, 1559340000000, 1567288800000];
let aSerie = dates.map((e, i) => [e, i < 5 ? null : i]);
let bSerie = dates.map((e, i) => [e, i + 1]);
let cSerie = dates.map((e, i) => [e, i * 2]);
Highcharts.stockChart('container', {
chart: {
events: {
load: function() {
const chart = this;
setTimeout(() => {
chart.series[1].update({
showInNavigator: false
});
}, 2000);
}
}
},
rangeSelector: {
verticalAlign: 'top'
},
series: [{
name: "aSerie",
showInNavigator: true,
data: aSerie
}, {
name: "bSerie",
showInNavigator: true,
data: bSerie
}, {
name: "cSerie",
showInNavigator: true,
data: cSerie
}]
});
Demo:
https://jsfiddle.net/BlackLabel/pxw09zrc/
API reference:
https://api.highcharts.com/highstock/series.line.showInNavigator
https://api.highcharts.com/class-reference/Highcharts.Series#update

Issue formatting data in JavaScript for a pie chart

I am not a JavaScript expert and I am trying to put a simple pie chart together using the data from a csv file. The sample code for the pie chart with its input data looks like below and it works perfectly.
var pie = new d3pie("pie", {
header: {
title: {
text: "A Very Simple Pie",
fontSize: 30
}
},
data: {
content: [
{ label: "JavaScript", value: 264131 },
{ label: "Ruby", value: 218812 },
{ label: "Java", value: 157618}
]
}
});
but when I try to use the data from the csv file. It says no data is provided. I obviously try to pass the dynamic data to the data.content but it seems like I am not doing it correctly. Below is my code:
var input_data = []
d3.csv("data.csv", function (data) {
input_data.push({
label: data["First"],
value: +data["Age"]
});
});
console.log(input_data); // This shows [{label: "james", value:30},{"John",value:22}]
var pie = new d3pie("pie", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: input_data
}
});
Any idea what I am doing wrong here?
As noted in my comment, your problem is because d3.csv acts asynchronously, and input_data isn't populated when d3pie tries to create your chart.
There is something highly suspicious going on with input_data in the other examples -- it should be called for every item in data, but seems only to be called once. Rather than using input_data to collate intermediate results, it's much easier to use javascript's map function to transform your csv data into the format you want:
d3.csv("data.csv", function (data) {
var pie = new d3pie("pie", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: data.map( function(d){
return { label: d['First'], value: +d['Age'] }
})
}
});
});
map iterates over an array and produces an array as output, so it's much cleaner and easier than creating extra arrays on to which you push data, etc.
You probably want to put your d3pie code inside your callback function because you want to call it after the data returns (see this example):
var input_data = []
d3.csv("data.csv", function (data) {
input_data.push({
label: data["First"],
value: +data["Age"]
});
console.log(input_data); // This shows [{label: "james", value:30},{"John",value:22}]
var pie = new d3pie("pie", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: input_data
}
});
});
const promise = d3.csv("data.csv", function (data) {
input_data.push({
'label': data["First"],
'value': +data["Age"]
});
});
promise.then(function(){
var pie = new d3pie("pieChart", {
header: {
title: {
text: "Simple Pie",
fontSize: 30
}
},
data: {
content: input_data
}
});
});

Chart.js chart in vue.js component does not update

I´m developing a visualization module for some crypto portfolios with vue.js and chart.js but am currently stuck with this:
Empty chart is displayed but non of the values are rendered.
Since the values are dynamically loaded after the chart is initialized I believe that the chart is not updating itself properly (even though I call .update()), but no errors are displayed whatsoever.
I wrapped the chart.js rendering in a vue component:
Vue.component('portfolioValues', {
template: '<canvas width="400" height="200"></canvas>',
data: function() {
return {
portfolio_value: [],
portfolio_labels: [],
chart: null,
}
},
methods: {
load_portfolio_value_local: function() {
values = [];
labels = []
local_data.forEach(element => {
values.push(element.total_usd);
labels.push(moment(element.timestamp, 'X'));
});
this.portfolio_value = values;
this.portfolio_labels = labels;
this.chart.update();
},
render_chart: function() {
this.chart = new Chart(this.$el, {
type: 'line',
data: {
labels: this.portfolio_labels,
datasets: [{
label: "Portfolio Value",
data: this.portfolio_value,
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
distribution: 'linear',
}]
}
}
});
}
},
mounted: function() {
this.render_chart();
this.load_portfolio_value_local();
}
});
For demonstration purposes I just added some data locally, looks like this:
local_data = [{
"timestamp": 1515102737,
"total_btc": 0.102627448096786,
"total_usd": 1539.41274772627
}, {
"timestamp": 1515102871,
"total_btc": 0.102636926127186,
"total_usd": 1538.52649627725
}, {
"timestamp": 1515103588,
"total_btc": 0.102627448096786,
"total_usd": 1532.33042753311
}
]
Here is the full demo code: https://codepen.io/perelin/pen/mppbxV
Any ideas why no data gets rendered? thx!
The problem you have here is how vuejs handles its data.
If you use it like that:
local_data.forEach(element => {
this.portfolio_value.push(element.total_usd);
this.portfolio_labels.push(moment(element.timestamp, 'X'));
});
this.chart.update();
The chart will update. But by re-initializing the arrays you work against vuejs.
TL;DR
If you want to re-initialize an object, you could assign the array to the object:
Object.assign(this.portfolio_value, values);
Object.assign(this.portfolio_labels, labels);
That way, the linking stays working.

Chartjs - Graphics Value type float

I have two graphs of the Chartjs and I need the values of both graphs to have broken values, for example (20,15);
Follow the graphics codes:
vm.chart = () => {
vm.labels = ["D1", "VC1", "Internacional", "À cobrar", "0300", "Gratuita", "Locais"];
vm.colors = [ '#f36e20', '#8aca7b', '#0bc4df', '#272343', '#389223', '#f1a80a', '#1e75eb'];
vm.data = [10, 10, 20, 10, 10, 10, 30];
vm.options = {
data: [
]
}
}
html:
<canvas class="chart chart-doughnut"
chart-data="vm.data"
chart-labels="vm.labels"
chart-colors="vm.colors"
chart-options="vm.options"
ng-init="vm.chart()">
</canvas>
Second chart:
vm.chart_gasto = () => {
vm.data_labels = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","21","23","24","25","26","27","28","29","30","31"];
vm.data_gasto = [85,55,85,105,55,85,35,95,85,64,25,85,25,55,85,25,85,64,85,25,64,35,85,35,55,85,35,85,35,85,105];
vm.data_colors = ['#8aacdf', '#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf','#8aacdf'];
vm.data_options = {
scales:{
yAxes:[{
display: false
}],
xAxes:[{
display: true,
gridLines: {
color: 'rgba(255,255,255,.35)'
},
ticks: {
fontColor: '#9d9d9c'
}
}]
}
}
}
html:
<canvas class="chart chart-bar" height="250px"
chart-data="vm.data_gasto"
chart-colors="vm.data_colors"
chart-labels="vm.data_labels"
chart-options="vm.data_options"
ng-init="vm.chart_gasto()">
</canvas>
In addition to "broken" numbers, is there a possibility for the% value next to them?
Has anyone ever had to do something similar?
Based on ChartJS documentation:
The tooltip label configuration is nested below the tooltip
configuration using the callbacks key. The tooltip has the following
callbacks for providing text. For all functions, 'this' will be the
tooltip object created from the Chart.Tooltip constructor.
All functions are called with the same arguments: a tooltip item and
the data object passed to the chart. All functions must return either
a string or an array of strings. Arrays of strings are treated as
multiple lines of text.
In your case if I am not mistaken this applies to something like this:
vm.options = {
tooltips: {
callbacks: {
label: (tooltipItem, chart) => {
const realValue = chart.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]
const customValue = realValue.toFixed(2).replace(".", ",") + '%';
const label = chart.labels[tooltipItem.index] + ':';
return label + customValue;
}
}
}
}
Here's a working fiddle with the code you shared.

Categories